-
Notifications
You must be signed in to change notification settings - Fork 3
/
atom.xml
4829 lines (3461 loc) · 314 KB
/
atom.xml
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[Category: railsontherun.com | Matt Aimonetti]]></title>
<link href="http://matt.aimonetti.net/articles/categories/railsontherun-com/atom.xml" rel="self"/>
<link href="http://matt.aimonetti.net/"/>
<updated>2012-04-20T17:24:59+02:00</updated>
<id>http://matt.aimonetti.net/</id>
<author>
<name><![CDATA[Matt Aimonetti]]></name>
</author>
<generator uri="http://octopress.org/">Octopress</generator>
<entry>
<title type="html"><![CDATA[Speed up your Rails XML responses]]></title>
<link href="http://matt.aimonetti.net/posts/2010/02/22/speed-up-your-rails-xml-responses/"/>
<updated>2010-02-22T23:25:09+01:00</updated>
<id>http://matt.aimonetti.net/posts/2010/02/22/speed-up-your-rails-xml-responses</id>
<content type="html"><![CDATA[<p>At <a href="http://www.us.playstation.com/">work</a>, we have an XML API that gets quite a lot of traffic. Last week I looked into improving its performance since we are expecting more traffic soon and want to make sure our response time is optimized.</p>
<p>My first thought was to make sure we had an optimized <a href="http://api.rubyonrails.org/classes/ActiveSupport/XmlMini.html">ActiveSupport's xmlmini backend</a>. Rails 2.3.5 fixed some issues when using <a href="http://nokogiri.org/">Nokogiri</a> as a xmlmini so I switched to my favorite Ruby XML lib:</p>
<pre><code>ActiveSupport::XmlMini.backend = 'Nokogiri'
</code></pre>
<p>I run some benchmarks using ab, httperf and jmeter but the results were not that great. I was so sure that switching from <a href="http://ruby-doc.org/stdlib/libdoc/rexml/rdoc/index.html">rexml</a> to <a href="http://nokogiri.org/">nokogiri</a> would give me awesome results that I was very disappointed.</p>
<p>I was about to call <a href="http://tenderlovemaking.com/">Aaron Patterson</a> (Nokogiri's author) to insult him, blame him for _why's disappearance and tell him that all his pro bono efforts were useless since my own app was not running much faster when switched to his library. As I was about to dial his number on my iPhone I had a crazy thought... maybe it was not Aaron's fault, maybe it was mine.</p>
<p>So I took a break went to play some fuzzball and as I was being ridiculed by Italian coworker, Emanuele, I realized that most of our API calls were just simple HTTP requests with no XML payload, just some query params. However, we were generating a lot of XML to send back to the client and AS::XmlMini only takes care of the XML parsing, not the rendering.</p>
<p>The XML rendering is done by <a href="http://onestepback.org/">Jim Weirich</a>'s pure Ruby <a href="http://builder.rubyforge.org/">builder library</a> which is vendored in Rails. Builder does a good job, but I thought that maybe a C based library might improve the speed. A coworker of mine (James Bunch) recommended to look into <a href="http://github.com/codahale/faster-builder">faster-builder</a>, a drop-in Builder replacement based on libxml. Unfortunately, the project doesn't seem to be maintained and I decided to look into using <a href="http://nokogiri.org/">Nokogiri</a> XML builder instead. (Also, faster-builder's author doesn't like me very much while Aaron knows he's one of my Ruby heroes so asking for help could be easier)</p>
<p>Some people reported having tried using <a href="http://nokogiri.org/">Nokogiri</a> as a XML builder but didn't see much speed improvement. Because of the amount of magic required to render a rxml template, I was not really surprised but I decided to contact Aaron and ask him if he tried using his lib instead of builder in a Rails app. <a href="http://www.flickr.com/photos/aaronp/57241193/">Aaron</a> told me he gave it a try a while back and he helped me get my Rails app setup to render xml templates using <a href="http://nokogiri.org/">Nokogiri</a>.</p>
<p>The next step was simple, create a <a href="http://github.com/mattetti/noko-vs-builder-benchmark">benchmark app</a> and benchmark Builder vs Nokogiri using various templates. Here are the results I got using Ruby 1.9.1 (the Ruby version we use in production) and two sets of templates:</p>
<p><strong>Builder</strong> small template, <strong>time per request: 15.507 [ms]</strong> (mean)</p>
<pre><code>$ ab -c 1 -n 200 http://127.0.0.1:3000/benchmarks/builder_small
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking 127.0.0.1 (be patient)
Completed 100 requests
Completed 200 requests
Finished 200 requests
Server Software: nginx/0.7.65
Server Hostname: 127.0.0.1
Server Port: 3000
Document Path: /benchmarks/builder_small
Document Length: 216 bytes
Concurrency Level: 1
Time taken for tests: 3.101 seconds
Complete requests: 200
Failed requests: 0
Write errors: 0
Total transferred: 114326 bytes
HTML transferred: 43200 bytes
Requests per second: 64.49 [#/sec] (mean)
Time per request: 15.507 [ms] (mean)
Time per request: 15.507 [ms] (mean, across all concurrent requests)
Transfer rate: 36.00 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 0.0 0 0
Processing: 11 15 8.8 12 47
Waiting: 3 15 8.9 12 47
Total: 11 15 8.8 12 47
Percentage of the requests served within a certain time (ms)
50% 12
66% 12
75% 13
80% 13
90% 35
95% 36
98% 38
99% 41
100% 47 (longest request)
</code></pre>
<p><strong>Nokogiri</strong> small template, <strong>time per request: 15.354 [ms] (mean)</strong></p>
<pre><code>$ ab -c 1 -n 200 http://127.0.0.1:3000/benchmarks/noko_small
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking 127.0.0.1 (be patient)
Completed 100 requests
Completed 200 requests
Finished 200 requests
Server Software: nginx/0.7.65
Server Hostname: 127.0.0.1
Server Port: 3000
Document Path: /benchmarks/noko_small
Document Length: 238 bytes
Concurrency Level: 1
Time taken for tests: 3.071 seconds
Complete requests: 200
Failed requests: 0
Write errors: 0
Total transferred: 118717 bytes
HTML transferred: 47600 bytes
Requests per second: 65.13 [#/sec] (mean)
Time per request: 15.354 [ms] (mean)
Time per request: 15.354 [ms] (mean, across all concurrent requests)
Transfer rate: 37.75 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 0.0 0 0
Processing: 11 15 8.6 12 39
Waiting: 11 15 8.6 12 39
Total: 11 15 8.6 12 39
Percentage of the requests served within a certain time (ms)
50% 12
66% 12
75% 12
80% 13
90% 35
95% 36
98% 37
99% 38
100% 39 (longest request)
</code></pre>
<p>Running the benchmarks many times showed that Nokogiri and Builder were taking more or less the same amount of time to builder a small template.</p>
<p>I then decided to try a bigger template, closer to what we have in production, here are the results:</p>
<p><strong>Nokogiri</strong> longer template, <strong>time per request: 31.252 [ms] (mean)</strong></p>
<pre><code>$ ab -c 1 -n 200 http://127.0.0.1:3000/benchmarks/noko
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking 127.0.0.1 (be patient)
Completed 100 requests
Completed 200 requests
Finished 200 requests
Server Software: nginx/0.7.65
Server Hostname: 127.0.0.1
Server Port: 3000
Document Path: /benchmarks/noko
Document Length: 54398 bytes
Concurrency Level: 1
Time taken for tests: 6.250 seconds
Complete requests: 200
Failed requests: 0
Write errors: 0
Total transferred: 10951200 bytes
HTML transferred: 10879600 bytes
Requests per second: 32.00 [#/sec] (mean)
Time per request: 31.252 [ms] (mean)
Time per request: 31.252 [ms] (mean, across all concurrent requests)
Transfer rate: 1711.00 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 0.0 0 0
Processing: 24 31 11.3 26 62
Waiting: 23 30 11.3 24 61
Total: 24 31 11.3 26 62
Percentage of the requests served within a certain time (ms)
50% 26
66% 27
75% 27
80% 29
90% 54
95% 55
98% 58
99% 59
100% 62 (longest request)
</code></pre>
<p><strong>Builder</strong>, longer template, <strong>Time per request: 140.725 [ms] (mean)</strong></p>
<pre><code>$ ab -c 1 -n 200 http://127.0.0.1:3000/benchmarks/builder
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking 127.0.0.1 (be patient)
Completed 100 requests
Completed 200 requests
Finished 200 requests
Server Software: nginx/0.7.65
Server Hostname: 127.0.0.1
Server Port: 3000
Document Path: /benchmarks/builder
Document Length: 54376 bytes
Concurrency Level: 1
Time taken for tests: 28.145 seconds
Complete requests: 200
Failed requests: 0
Write errors: 0
Total transferred: 10947000 bytes
HTML transferred: 10875200 bytes
Requests per second: 7.11 [#/sec] (mean)
Time per request: 140.725 [ms] (mean)
Time per request: 140.725 [ms] (mean, across all concurrent requests)
Transfer rate: 379.83 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 0.1 0 1
Processing: 127 141 24.6 132 331
Waiting: 126 139 23.6 130 328
Total: 127 141 24.6 132 331
Percentage of the requests served within a certain time (ms)
50% 132
66% 138
75% 147
80% 149
90% 156
95% 169
98% 193
99% 311
100% 331 (longest request)
</code></pre>
<p>Wow, <a href="http://twitter.com/tenderlove">@tenderlove</a>'s Nokogori just brought us a<strong> 4.5X speed improvement for this specific template</strong>. 100ms per request is probably not a big deal for most people and I have to say that Jim did a great job with Builder. However in my specific case, 100ms on a request being called thousands of times per hour is quite important.</p>
<p>(The <a href="http://github.com/mattetti/noko-vs-builder-benchmark">benchmark app is available on github</a>, feel free to fork it and benchmark your own templates)</p>
<p>Who would have thought that a man like this could save the day?!</p>
<p>[caption id="attachment_1737" align="alignleft" width="150" caption="Aaron 'Tenderlove' Patterson"]<a href="http://railsontherun.com/wp-content/uploads/2010/02/aaron.jpg"><img src="http://railsontherun.com/wp-content/uploads/2010/02/aaron-150x150.jpg" alt="" /></a>[/caption]</p>
<p><a href="http://www.flickr.com/photos/aaronp/3824959062/"><img src="http://farm3.static.flickr.com/2470/3824959062_fb0755e665_m_d.jpg" alt="" /></a></p>
<p><a href="http://www.flickr.com/photos/aaronp/57241193/"><img src="http://farm1.static.flickr.com/29/57241193_8137f2a4af_m_d.jpg" alt="" /></a></p>
<p><a href="http://www.flickr.com/photos/aaronp/3132124227/"><img src="http://farm4.static.flickr.com/3289/3132124227_3ace4ec7ae_m_d.jpg" alt="" /></a></p>
<p><strong><em>The moral of the story is that adding a bit of tenderlove to your Ruby code can make it perform much much better!</em></strong></p>
<p><strong>Thank you Aaron 'Tenderlove' Patterson!</strong></p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[Googlecharts 1.5.1]]></title>
<link href="http://matt.aimonetti.net/posts/2010/02/03/googlecharts-1-5-1/"/>
<updated>2010-02-03T21:18:23+01:00</updated>
<id>http://matt.aimonetti.net/posts/2010/02/03/googlecharts-1-5-1</id>
<content type="html"><![CDATA[<p>To celebrate the relaunch of this site and since we are waiting for Rails 3.0 beta to be released, I figured I should share with you what I worked on the other night.</p>
<p>I merged patches, refactored and released a new version of googlecharts, my Gem to create graphs using Google Chart API.</p>
<p><code>sudo gem install googlecharts</code></p>
<p>Here is a quick example of how the API works when dealing with a complex graph:</p>
<pre><code>require 'gchart' # or require 'googlecharts' if you prefer to use the Googlecharts constant.
title = "Player Count"
size = "575x300"
data = [85,107,123,131,155,172,173,189,203,222,217,233,250,239,256,267,247,261,275,295,288,305,322,307,325,347,331,346,363,382,343,359,383,352,374,393,358,379,396,416,377,398,419,380,409,426,453,432,452,465,436,460,480,440,457,474,501,457,489,507,347,373,413,402,424,448,475,488,513,475,507,530,440,476,500,518,481,512,531,367,396,423,387,415,446,478,442,469,492,463,489,508,463,491,518,549,503,526,547,493,530,549,493,520,541,564,510,535,564,492,512,537,502,530,548,491,514,538,568,524,548,568,512,533,552,577,520,545,570,516,536,555,514,536,566,521,553,579,604,541,569,595,551,581,602,549,576,606,631,589,615,650,597,624,646,672,605,626,654,584,608,631,574,597,622,559,591,614,644,580,603,629,584,615,631,558,591,618,641,314,356,395,397,429,450,421,454,477,507,458,490,560,593]
Gchart.line(:title => title, :size => size, :data => data, :axis_with_labels => 'x,y', :line_color => '1e60cc', :axis_labels => [(1.upto(24).to_a << 1)], :max_value => 700, :custom => 'chg=10,15,1,0')
</code></pre>
<p>Which provides you with the url or image tag (or downloaded file) that produces the following graph:</p>
<p><img src="http://chart.apis.google.com/chart?chxl=0:|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|1&chxt=x,y&chco=1e60cc&chg=10,15,1,0&chd=s:HJKLNPPQRTTUWVWXVXYaZbcbcedeghefhfhifhjkhjlhklomopmoqmopsorsehkjlnqrtqsumqstqtvgjliknqnprprsprtwsuwruwruvxtvxrtvsuwrtvyuwytvwzuwytvxtvyuwz1vy0wz1wz130250357135z13y03x025z13z23x024bfijlnloqsorx0&chtt=Player+Count&cht=lc&chs=575x300&chxr=1,85,700" alt="Google Chart" /></p>
<p>This release works great with Ruby 1.9 and <a href="http://macruby.org">MacRuby</a>, lots of bugs got fixed and some new features were added. Something a lot of people complained was that the gem was called googlecharts but that the main class was called Gchart. The problem was that I wrote my gem and called it Gchart and when I went to register the rubyforge project page, the name was already taken. In this release, I fixed this problem by allowing users to require and use the constant name they want, Gchart or Googlecharts. I also spent quite a lot of time cleaning up the old code which I was a bit ashamed of. Class variables are now removed and overall, the code should be a bit more sane.</p>
<p>The source code can be found in my <a href="http://github.com/mattetti/googlecharts/">GitHub accout</a> and the documentation <a href="http://mattetti.github.com/googlecharts/">there</a>.</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[Rails and Merb core team working together]]></title>
<link href="http://matt.aimonetti.net/posts/2008/12/24/rails-and-merb-core-team-working-together/"/>
<updated>2008-12-24T08:47:00+01:00</updated>
<id>http://matt.aimonetti.net/posts/2008/12/24/rails-and-merb-core-team-working-together</id>
<content type="html"><![CDATA[<h3>This is huge!</h3>
<p><img src="http://merbist.com/wp-content/uploads/2008/12/surprise-296x300.jpg" alt="" /></p>
<p>While people still try to find some drama an in hypothetical war between rails and merb.</p>
<p>The Rails team and the Merb team announced working together on a joined version of the 2 frameworks. This is so exciting, nobody believed it could ever happen (I personally, had my serious doubt).</p>
<p>Yehuda had a great post laying down the plan and explaining things in details. Check out David’s post explaining why he wants us to work together and his vision of a better Ruby world.</p>
<p>I have to say that I have been impressed by the Rails core team and especially David (DHH).</p>
<p>I’ve known David for few years now and we had long/heated discussions on topics like i18n/l10n for Rails. David is known to be a very opinionated person. But if you come up with the right arguments, he can be convinced and when that happens, he is willing to move forward and shake things up.</p>
<p>This merge is a concrete example that David and the rest of the Rails team cares about Rails and the Ruby community more than we usually give them credit for. As a unified team, we are going to change the way web development in Ruby is done!</p>
<p>But what does it mean for you?</p>
<p>I put together a FAQ video here is the transcript:</p>
<p>Hi, I’m Matt Aimonetti from the merb core team and as you might have heard, a big announcement was made earlier today.</p>
<p>I did this video to hopefully answer the questions you might have.</p>
<h3>Q: So what’s the big news?</h3>
<ul>
<li><p>merb and rails team will work together on the next version of their frameworks</p></li>
<li><p>merb 2.0 and rails 3.0 share the same common endpoint</p></li>
<li><p>we realized we now have the same objectives and agreed on all the key principles.</p></li>
<li><p>merb will provide Rails with agnosticism, modularity, improved performance and a public API.</p></li>
<li><p>The end product will be called Rails 3.0 but what real matters is that it’s a huge gain for the entire community.</p></li>
</ul>
<h3>Q: What??? I thought there was a war going on between Rails and merb, what happened?</h3>
<ul>
<li><p>There was no war between rails and merb</p></li>
<li><p>We created merb because rails was not fitting us</p></li>
<li><p>We wanted better performance, more choices/ more modularity and a Public API.</p></li>
<li><p>The Rails team now embraces these concepts and want Rails to follow them, so why not work together?</p></li>
</ul>
<h3>Q: Wait, does that mean that merb is dead?</h3>
<ul>
<li><p>Absolutely not!</p></li>
<li><p>merb development won’t stop, we are going to keep on releasing updates until rails 3.0</p></li>
<li><p>clear migration path, and upgrading to rails 3.0 will be as trivial as upgrading from rails 2.x to Rails 3.0</p></li>
</ul>
<h3>Q: What does the timeline look like?</h3>
<p>We just started getting together and discuss the technical details. We are shooting for a release at RailsConf 2009. However it’s hard to estimate this kind of things so again, that’s just an estimate <img src="http://merbist.com/wp-includes/images/smilies/icon_smile.gif" alt=":)" /></p>
<h3>Q: I just started a merb project, so what now?</h3>
<p>I’m sure you had valid reasons to use merb, you needed modularity, performance and a solid API.</p>
<p>Keep on using Merb, we won’t let you down. The good news is that the next version of merb (rails 3.0) will be even awesomer!</p>
<h3>Q: What about my client who was looking at using merb for his new project?</h3>
<p>If your client is going to be using merb for valid reasons (and not, just because it’s not rails) he should still use merb, but with the full understanding that he/she will end up using Rails in 6 months or so. Again, Rails 3.0 will have what pushed you to use merb.</p>
<h3>Q: I’ve been involved with the merb-book, what will happen with this project?</h3>
<ul>
<li><p>rails 3.0 won’t get released right away</p></li>
<li><p>still need awesome documentation</p></li>
<li><p>if we look at rails 3.0 as merb 2.0, we can easily imagine how the current work can be extended to the new version.</p></li>
<li><p>rails team will also include an evangelism team which I will be part of, so will be able to focus more on projects like the book.</p></li>
</ul>
<h3>Q: I’ve been working on a merb plugin, what should I do?</h3>
<p>Keep working on it! We’ll assist you with the migration process and the new solid API.</p>
<h3>Q: What if I still have questions?</h3>
<p>Come talk with me, or any members from the new team. We’ll be open to hear your questions, worries, frustrations.</p>
<p>merb always valued its developers and we will continue to do so but at a bigger scale.</p>
<hr />
<p>Concretely, nothing changes for Merb users. People loving Merb should not worry. The way you build merb apps won’t change until merb2.0/rails3.0. We will still work on your favorite framework and improve it.</p>
<p>Lori Holden worked on merb_sequel and we should release a 1.0 release of the plugin in a few days.</p>
<p>I’m sure this news comes as a shock for many of you, but try to not see Rails 3.0 as the way Rails is right now. Imagine a version of Rails with true modularity and agnosticism (sequel, DM and AR will still be supported) and the same type of performance as what you get with Merb. In other words, the rails world is about to discover the power of merb!</p>
<p>Here is what Yehuda explicitly says in his blog post:</p>
<ul>
<li><p>Rails will become more modular, starting with a rails-core, and including the ability to opt in or out of specific components. [...]</p></li>
<li><p>We will port all of our performance improvements into Rails. This includes architectural decisions that are big performance wins.[..]</p></li>
<li><p>As of Rails 3, Rails will have a defined public API with a test suite for that API. [..]</p></li>
<li><p>Rails will still ship with the “stack” version as the default (just as Merb does since 1.0), but the goal is to make it easy to do with Rails what people do with Merb today.</p></li>
<li><p>Rails will be modified to more easily support DataMapper or Sequel as first-class ORMs. [..]</p></li>
<li><p>Rails will continue their recent embrace of Rack, which [..] will improve the state of modular, sharable logic between applications.</p></li>
<li><p>In general, we will take a look at features in Merb that are not in Rails (the most obvious example is the more robust router) and find a way to bring them into Rails.</p></li>
</ul>
<h2>Personal perspective</h2>
<p>I’m personally really excited about this opportunity. I had a hard time believing that we could work together but I was proved wrong. We have many challenges in front of us, but watching the two teams working together is very reassuring.</p>
<p>I’m also glad to see that we will have a Rails Evangelism team that I will be part of. I strongly believe that one of the many reasons why merb has been so successful is because we work and listen to our community. We have put a tremendous amount of energy trying to understand what you guys need and what you like and dislike. In return, we saw many people working hard on the wiki and the merb-book.</p>
<p>Can you imagine doing that with almost 4 Million Rails developers?</p>
<p>I’m also looking forward to working with a team and reaching to even more people.</p>
<h2>Other news related to the merge:</h2>
<ul>
<li><p>The RubyOnRails website will keep a trace of this historical moment: <a href="http://rubyonrails.org/merb">http://rubyonrails.org/merb</a></p></li>
<li><p>The <a href="http://merbclass.com/">merb training scheduled for Jan 19-21</a> in partnership with <a href="http://integrumtech.com/">Integrum</a> will still take place, and if you want to get a head start and learn about the things that will make Rails 3.0 totally kick ass, I’d suggest you join us.</p></li>
</ul>
<p>If you have any questions, or if you want me to publicly answer questions on your blog please contact me. I’ll do my best to get back to everyone.</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[MerbCamp 2008 SanDiego]]></title>
<link href="http://matt.aimonetti.net/posts/2008/09/16/merbcamp-2008-sandiego/"/>
<updated>2008-09-16T06:27:00+02:00</updated>
<id>http://matt.aimonetti.net/posts/2008/09/16/merbcamp-2008-sandiego</id>
<content type="html"><![CDATA[<p><img src="http://merbivore.com/img/merbcamp_badge_200.gif" alt="merbcamp" /></p>
<p>That's now finally <a href="http://www.reuters.com/article/pressRelease/idUS113181+09-Sep-2008+PRN20080909">official</a>, <a href="http://merbcamp.com">MerbCamp</a> 2008 <a href="http://merbcamp.com/#registration">registration</a> are open! What an exciting time!</p>
<h2>History</h2>
<p>To understand why I'm excited, we need to go back few months back. Merb was first released by <a href="http://brainspl.at/">Ezra</a> has an alternative tool to handle file uploads. Merb came to reality because Ezra needed something fast, light and flexible to handle something that, let's be frank about it, Rails had a hard time dealing with. Rails was king but was not as popular as now. Merb started as a simple Mongrel handler, in other words an alternative for small, light limited actions. Most people started using Merb simply to handle uploads. But as few cool kids started using Merb, they thought, hey, this thing is super fast, maybe I can use it to build small standalone apps. After all, hardcore developers don't need "cool ajax helpers" and form builders to create a simple site. <a href="">Geoffrey Grosenback</a> aka topfunky even proudly used Merb to reduild his site!
That was just enough to convince me to start using Merb back at version 0.3.4.</p>
<p>I was an active Rails user and contributor. Having to use a bare bone Ruby web framework was quite refreshing however the lack of testing framework was a real show stopper :( (Being hooked up on RSpec by <a href="http://joshknowles.com">Josh Knowles</a> I ended up only writing a small portion of a Rails app with Merb 0.3.x (uploader backend).)</p>
<p>Quite quickly Merb's philosophy changed and switched. The Mongrel handler framework started dreaming of becoming an alternative to Rails. Merb took the best from Rails but targeted another audience: the Ruby hackers living on the edge.
Merb prides itself in being less opinionated than Rails(that can be argued tho), ORM agnostic (supporting ActiveRecord, Sequel and DataMapper), Javascript framework agnostic and truly modular. People like <a href="http://yehudakatz.com">Yehuda Katz</a>, <a href="http://merb.lighthouseapp.com/users/10354">Michael Klishin aka antares</a> got involved, as more contributors joined the effort, rules were enforced to make sure the framework would be as fast as possible and easy to extend without monkey patching. (ohh and fully tested using RSpec ;)</p>
<p><a href="http://engineyard.com">Engine Yard</a> decided to support the development effort and helped with Merb's major rewrite (0.9 versions). Today, Merb is divided in 3 repositories, merb-core, merb-more and merb-plugins. By letting developers only choose what they want to use and by following a principle of isolation with private/public APIs, I believe Merb is today the most flexible yet powerful Ruby framework available.
Furthermore, even though many people don't understand the purpose of rewriting a "new Rails" from scratch, the reality is that many progress made by the merb team were ported back to Rails and inspired others (DataMapper for instance)!</p>
<p>Anyway, this is not a sale's speech and I'm not trying to convince you to use Merb. My point is that Merb is finally coming to a point where the public API is stable and where one would find most tools he needs to build production ready applications.
And, that's basically a long sum up explaining why I wanted to organize something special to celebrate the 1.0 release and to create more awareness around Merb's awesomeness!</p>
<h2>The Team behind MerbCamp</h2>
<p>I started getting involved with the SDRuby community a couple of years ago. As I got to know more people I realized that many people lead by <a href="http://mokolabs.com">Patrick Crowley</a> (leader of SDRuby and one of the organizers of SD BarCamp) had the desire to organize a local Ruby conf/camp.</p>
<p>At the same time, while I was working daily with Merb and contributing back to Merb's code, many other SDRuby fellows were also getting really excited about Merb (<a href="http://notch8.com">Rob Kaufman</a>, <a href="http://">Ryan Felton</a> to mention a few).</p>
<p>Seeing the opportunity to host the very first Merb event in San Diego (host of RubyConf 2005!) I chatted with <a href="http://yehudakatz.com">yehuda</a> and the rest of the merb team. All the merb people were really excited, Leah Sibler from <a href="http://engineyard.com">Engine Yard</a> even offered her expertise to organize such an event (she's totally awesome at planning/running conferences).</p>
<p>However, setting up such an event isn't something one can do on his own. Before promising anything, I checked that Rubyists from San Diego would be interested and would help. In no time, I got a lot of people offering to help.</p>
<p>The key thing for me was to get someone with a good experience in organizing conferences. A person with resources and contacts. The only person I knew in San Diego who would be good enough to do that was <a href="http://mokolabs.com">Patrick Crowley</a>. We had a quick chat Patrick and I and it turned out that Patrick was very excited about organizing the very first MerbCamp in his town.
Patrick quickly got a team together who agreed on working on the project. We got back to the Merb team and sealed the deal.</p>
<p>Patrick even found the <a href="http://www.calit2.net/">awesome venue</a> that many other cities will envy us! He's been running the show, running here and there, making phone calls to make sure registration would open on time, setup the website etc.... Thanks Patrick!</p>
<h2>The Conf</h2>
<p>MerbCamp will be an hybrid between a BarCamp, a conference and an unconference. When the organization team got together, we all agreed that what we like the most during conferences is networking. We certainly also enjoy some good talks and definitely enjoyed the hack-room during the last Rails Conf. We therefore decided to organize a conf <em>*we</em>* would love to go.</p>
<ul>
<li><p>1 scheduled track with "official talks" to make sure we have some serious content and to motivate people to signup ;)</p></li>
<li><p>BBQ at the beach, because we live in San Diego and we love that! (plus, big open meals are the best way to network)</p></li>
<li><p>BarCamp type impromptu talks</p></li>
<li><p>hack-rooms so people can work together</p></li>
<li><p>friendly and small conference (we limited the amount of participants to 200)</p></li>
</ul>
<p>To conclude, I hope the "history" of MerbCamp 08 wasn't too boring. People seem quite excited about this event, we even have guys in London who would get together to watch the talks via a webcam we are going to setup for them.
We hope to see you there, if not, we hope you'll organize your own conference and we will come have fun with you.</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[db fixtures replacement solution step by step]]></title>
<link href="http://matt.aimonetti.net/posts/2008/09/07/db-fixtures-replacement-solution-step-by-step/"/>
<updated>2008-09-07T16:06:00+02:00</updated>
<id>http://matt.aimonetti.net/posts/2008/09/07/db-fixtures-replacement-solution-step-by-step</id>
<content type="html"><![CDATA[<p>Like most people who started with Rails a while back, I first loved Rails fixtures and ended up hating them (slow, a pain to maintain etc...).</p>
<p>I went through different experiments, trying different existing libs, writing my own solutions etc... I wasn't quite satisfied until I found <a href="http://github.com/thoughtbot/factory_girl">factory_girl</a> from <a href="http://www.thoughtbot.com/">thoughtbot</a>.</p>
<p>You might not feel the need for a decent fixtures solution if you do a lot of mocking/stubbing, but I recently came back from my "mock everything you can outside of models" approach and I'm getting closer to the <a href="http://snipr.com/3nwry">mock roles, not objects</a> approach. So, I'm loosing my model/controller testing separation but I'm gaining by not having to maintain "dumb mocks" which don't always represent the real API behind. I mean, how many times did I change a Model, messing up my app but all my specs were still passing. Anyway, that's a long discussion, which will be covered by <a href="http://yehudakatz.com/">wycats</a> during <a href="http://merbcamp.com">merbcamp</a></p>
<p>So here is a simple example of how I use <a href="http://github.com/thoughtbot/factory_girl">factory girl</a> in a Merb + DataMapper app. (you can do the same in a Rails app, there is <strong>nothing</strong> specific to Merb in factory_girl).</p>
<ul>
<li><p>I. create an empty app, set the ORM etc...</p></li>
<li><p>II. git pull and install factory_girl from <a href="http://github.com/thoughtbot/factory_girl/tree/master">http://github.com/thoughtbot/factory</a>_<a href="http://github.com/thoughtbot/factory_girl/tree/master">girl/tree/master</a>. Or install thoughtbot-factory_girl gem using <a href="http://gems.github.com">GitHub gem server</a>.</p></li>
<li><p><strong>III.</strong> create a spec/factories.rb file. (You might prefer to create a folder called spec/factories and add a factory per model)</p></li>
<li><p><strong>IV.</strong> modify spec_helper.rb and add the following</p>
<p> require 'factory_girl'
require File.dirname(<strong>FILE</strong>) + '/factories'</p></li>
<li><p>V. write some specs against a Client model</p></li>
<li><p><strong>VI.</strong> Create the Model</p></li>
<li><p><strong>VII.</strong> create a factory</p></li>
<li><p><strong>IIX.</strong> run your specs</p></li>
</ul>
<p><img src="http://img.skitch.com/20080907-tf8yy6fi82b23t78stqii3mpbe.jpg" alt="failing specs" /></p>
<ul>
<li><p><strong>IX.</strong> fix the model (note that I set <code>dependencies "dm-validations"</code> in my init.rb)</p></li>
<li><p>X. run the specs</p></li>
</ul>
<p><img src="http://img.skitch.com/20080907-m7p2r6q1qau4k3qsmeadwu2tur.jpg" alt="passing specs" /></p>
<ul>
<li><strong>XI.</strong> add more specs</li>
</ul>
<p>As you can see, Factory.build(:client) only creates a new instance of the Object, while Factory(:client) creates, saves and loads the instance.</p>
<ul>
<li><strong>XII.</strong> get them to pass</li>
</ul>
<p>Factory Girl makes fixtures simple and clean. Here is another example for creating associations:</p>
<p>Factory Girl also supports sequencing, check out FG <a href="http://github.com/thoughtbot/factory_girl">read me</a></p>
<h2>In conclusion, Factory Girl is a mature and solid factory solution which will take you less than 15 minutes to get used to. It will offer you loads of flexibility and less frustration than good old yaml fixtures. You can also use it with existing fixtures if you want to start using it in an existing app.</h2>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[Ruby developers don't scale]]></title>
<link href="http://matt.aimonetti.net/posts/2008/08/27/ruby-developers-don-t-scale/"/>
<updated>2008-08-27T14:58:00+02:00</updated>
<id>http://matt.aimonetti.net/posts/2008/08/27/ruby-developers-don-t-scale</id>
<content type="html"><![CDATA[<p>Wow, it's been a while since I blogged. With all the cool kids saying that spending time reading RSS feeds is overrated (see <a href="http://rubyhoedown2008.confreaks.com/08-chris-wanstrath-keynote.html">Defunkt's keynote</a> for instance) I even wonder if people will ever read this post!</p>
<p>Anyways, I have been quite busy preparing courses for classes I gave to a bunch a great Engineers at one of the Fortune 100 companies based in San Diego. I was also planning my big vacation trip to Europe and wrapping up few projects.</p>
<p>However, during my exile overseas, I came to the conclusion that <strong>Rubyists don't scale</strong>. Since Twitter became stable again, we don't hear many people ranting about Rails not scaling anymore. With one of my clients' app handling around <strong>7 million requests/day</strong> I can tell you <strong>Ruby/Merb do scale quite well</strong>! But ruby developers don't seem to scale for some reason.</p>
<p>Maybe saying that we(Rubyists) don't scale isn't technically correct but that's basically what one of my client told me.</p>
<p>Let's go back in time a little bit and follow my client who we will call clientX.</p>
<ul>
<li><p>ClientX has a <strong>great concept</strong> and wants to conquer the internet.</p></li>
<li><p>ClientX hears that <strong>Rails is the way to go</strong>.</p></li>
<li><p>ClientX hires a contractor/mercenary/freelancer/guns for hire/<strong>consultant</strong> (aka Me)</p></li>
<li><p>Me builds a <strong>killer app</strong> using <strong>Merb</strong> (killing framework)</p></li>
<li><p>ClientX raises loads of <strong>$$$</strong></p></li>
<li><p>ClientX <strong>wants to hire a team</strong> because Me doesn't want to become a FTE</p></li>
<li><p>ClientX and Me <strong>look for Rubyists</strong> wanting to relocate and get a decent salary</p></li>
<li><p>ClientX <em>*can't find someone</em> they consider good enough and who would accept their package</p></li>
<li><p>Many <strong>JAVA guys are available</strong> on location and accept lower packages</p></li>
<li><p><strong>Ruby app gets ported over to JAVA</strong></p></li>
<li><p><strong>Me sad</strong> :(</p></li>
</ul>
<p>So is it really the Rubyists' fault if we don't want to relocate and only accept higher packages? Should I blame <a href="http://blog.obiefernandez.com/">Obie</a> for telling people to charge more and teaching how to <a href="http://rubyhoedown2008.confreaks.com/07-obie-fernandez-do-the-hustle.html">hustle</a>? Or should we just tell clients that it's time to get used to working remotely?</p>
<p>Honestly, I don't think any of the above explanations are valid. Ruby is the new/hot technology and very few people have the skills and experience to lead major projects. These people make a good living and enjoy their "freedom" and dream of building their own products. Most of them/us value their work environment, family and are reluctant to move.</p>
<p><img src="http://img.skitch.com/20080827-rwca7tfprhce6hw19uytfqx1bc.jpg" alt="scale" /></p>
<p>At the same time, companies do need people locally(at least a core team) and can't always afford the cool kids.</p>
<p>ClientX, quite frustrated by the whole hiring process told me once: <strong>"you Ruby folks are too unavailable and difficult to work with! We need a committed team that actually cares about the company/product."</strong></p>
<p>That hurts when you worked hard on a project and just can't satisfy the client by finding guys willing to relocate and work for them. <strong>It gets even more painful when your code gets entirely ported over to JAVA!</strong></p>
<p>But at the same time I understand ClientX's motivation, PHP guys are cheaper, JAVA guys are more available, why in the word did we go with Ruby and are now struggling finding people?</p>
<p>Once again, there is positive and negative side in everything, by choosing Ruby and a "great contractor" ClientX was able to <strong>catch up with the competition and even pass them in no time</strong>. They quickly raised good money and got everything they needed to become #1. I don't believe it would have been possible to do the same thing so quickly with JAVA for instance. However choosing a cutting edge technology means you need to look harder for talented people.</p>
<p>It's too bad the code gets rewritten in a different language but at the same time, I do my best to facilitate the process and to keep a good relation with my client. There was nothing personal in the decision, it's just too bad we were not able to keep on using the latest/coolest/awesomess technology available :)</p>
<h2>To finish on a positive note, here is the solution to scale your Ruby task force provided to you by the #caboose wisdom:</h2>
<p>Based on my conversations with other #caboosers who hire other devs, the word in the street is that you just need to get one or two great ruby guys (who will probably cost you a lot) and find a bunch of smart people to train. You'll end up with an awesome team of scalable rubyists ;)</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[Googlecharts featured on Github]]></title>
<link href="http://matt.aimonetti.net/posts/2008/06/27/googlecharts-featured-on-github/"/>
<updated>2008-06-27T07:06:00+02:00</updated>
<id>http://matt.aimonetti.net/posts/2008/06/27/googlecharts-featured-on-github</id>
<content type="html"><![CDATA[<p><a href="http://github.com">Github</a>, probably the most famous social code hosting service just <a href="http://github.com/blog/103-new-homepage">redesigned their homepage</a> and are now featuring hosted projects.</p>
<p>I got a very good surprise when <a href="http://github.com/takeo">Takeo</a> from <a href="http://powerset.com">Powerset</a> & <a href="http://stafftool.com">Stafftool</a> hall of fame mentioned to me that <a href="http://github.com">Github</a> picked one of my gems as the first featured project!</p>
<p><img src="http://img.skitch.com/20080627-r14subqdx2ye3w13qefbx974gc.png" alt="github" /></p>
<p>By the way, Takeo is also a Googlecharts contributor (+ a Merbist) and I had the honor to be the first one he ever forked!</p>
<p>Another Googlecharts user, <a href="http://graffletopia.com">Mokolabs</a> from Graffletopia and <a href="http://icalshare.com/">iCal Share</a> also decided to try Git and Github. In no time he had forked my project, made some modifications and sent me a pull request. w00t w00t!</p>
<p>To celebrate, we released version 1.3.4 with cleaner documentation, and enhanced features.</p>
<p><a href="http://googlecharts.rubyforge.org/">Documentation</a> & <a href="http://github.com/mattetti/googlecharts">Code Repo</a></p>
<p>Thanks to everyone involved in this project. And special kudos to the <a href="http://github.com">GitHub</a> team for offering such an awesome service!</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[About Metaprogramming speed]]></title>
<link href="http://matt.aimonetti.net/posts/2008/06/18/about-metaprogramming-speed/"/>
<updated>2008-06-18T07:03:00+02:00</updated>
<id>http://matt.aimonetti.net/posts/2008/06/18/about-metaprogramming-speed</id>
<content type="html"><![CDATA[<p>In a <a href="http://railsontherun.com/2008/5/4/avoid-using-metaprogramming">previous article</a> I took an example of bad metaprogramming and I pushed people to think twice before using metaprogramming.</p>
<p>My main points were that:</p>
<ul>
<li><p>you might make your code way slower if you don't know what you are doing</p></li>
<li><p>readability might drop considerably</p></li>
<li><p>maintainability can become an issue</p></li>
</ul>
<p>People left some very good comments about how to write the same module using metaprogramming and keep things fast.</p>
<p>Today <a href="http://yehudakatz.com">Wycats</a> pinged me about this post and told me that the issue was define_method and that class_eval is effectively the same as regular code, it gets evaluated in eval.c, just like regular Ruby code. On the other hand, defined_method has to marshall the proc.</p>
<p>I cleaned up my benchmarks using <a href="http://github.com/somebee/rbench/tree/master">rbench</a>, added some of the solutions provided to me and obtained the following results:</p>
<p><img src="http://img.skitch.com/20080618-ju8hy1b1pw8c3hb882ksr3hbed.jpg" alt="results" /></p>
<p>Here is the original/bad metaprogramming example:</p>
<pre><code>1<tt>
</tt>2<tt>
</tt>3<tt>
</tt>4<tt>
</tt><strong>5</strong><tt>
</tt>6<tt>
</tt>7<tt>
</tt>8<tt>
</tt>9<tt>
</tt><strong>10</strong><tt>
</tt>11<tt>
</tt>12<tt>
</tt>13<tt>
</tt>14<tt>
</tt><strong>15</strong><tt>
</tt>16<tt>
</tt>17<tt>
</tt>18<tt>
</tt>19<tt>
</tt>
<tt>
</tt> <span class="r">module</span> <span class="cl">MetaTimeDSL</span><tt>
</tt><tt>
</tt> {<span class="sy">:second</span> => <span class="i">1</span>, <tt>
</tt> <span class="sy">:minute</span> => <span class="i">60</span>, <tt>
</tt> <span class="sy">:hour</span> => <span class="i">3600</span>, <tt>
</tt> <span class="sy">:day</span> => [<span class="i">24</span>,<span class="sy">:hours</span>], <tt>
</tt> <span class="sy">:week</span> => [<span class="i">7</span>,<span class="sy">:days</span>], <tt>
</tt> <span class="sy">:month</span> => [<span class="i">30</span>,<span class="sy">:days</span>], <tt>
</tt> <span class="sy">:year</span> => [<span class="fl">364.25</span>, <span class="sy">:days</span>]}.each <span class="r">do</span> |meth, amount|<tt>
</tt> define_method <span class="s"><span class="dl">"</span><span class="il"><span class="dl">#{</span>meth<span class="dl">}</span></span><span class="dl">"</span></span> <span class="r">do</span><tt>
</tt> amount = amount.is_a?(<span class="co">Array</span>) ? amount[<span class="i">0</span>].send(amount[<span class="i">1</span>]) : amount<tt>
</tt> <span class="pc">self</span> * amount<tt>
</tt> <span class="r">end</span><tt>
</tt> alias_method <span class="s"><span class="dl">"</span><span class="il"><span class="dl">#{</span>meth<span class="dl">}</span></span><span class="k">s</span><span class="dl">"</span></span>.intern, <span class="s"><span class="dl">"</span><span class="il"><span class="dl">#{</span>meth<span class="dl">}</span></span><span class="dl">"</span></span><tt>
</tt> <span class="r">end</span><tt>
</tt><tt>
</tt> <span class="r">end</span><tt>
</tt> <span class="co">Numeric</span>.send <span class="sy">:include</span>, <span class="co">MetaTimeDSL</span><tt>
</tt>
</code></pre>
<p>The no metaprogramming module is available <a href="http://pastie.textmate.org/217046">there</a></p>
<p>Refactored:</p>
<pre><code>1<tt>
</tt>2<tt>
</tt>3<tt>
</tt>4<tt>
</tt><strong>5</strong><tt>
</tt>6<tt>
</tt>7<tt>
</tt>8<tt>
</tt>9<tt>
</tt><strong>10</strong><tt>
</tt>11<tt>
</tt>12<tt>
</tt>13<tt>
</tt>14<tt>
</tt><strong>15</strong><tt>
</tt>16<tt>
</tt>17<tt>
</tt>18<tt>
</tt>19<tt>
</tt><strong>20</strong><tt>
</tt>
<tt>
</tt> <span class="r">module</span> <span class="cl">RefaMetaTimeDSL</span><tt>
</tt><tt>
</tt> {<span class="sy">:second</span> => <span class="i">1</span>, <tt>
</tt> <span class="sy">:minute</span> => <span class="i">60</span>, <tt>
</tt> <span class="sy">:hour</span> => <span class="i">3600</span>, <tt>
</tt> <span class="sy">:day</span> => [<span class="i">24</span>,<span class="sy">:hours</span>], <tt>
</tt> <span class="sy">:week</span> => [<span class="i">7</span>,<span class="sy">:days</span>], <tt>
</tt> <span class="sy">:month</span> => [<span class="i">30</span>,<span class="sy">:days</span>], <tt>
</tt> <span class="sy">:year</span> => [<span class="fl">364.25</span>, <span class="sy">:days</span>]}.each <span class="r">do</span> |meth, amount|<tt>
</tt> <span class="pc">self</span>.class_eval <span class="s"><span class="dl"><<-RUBY</span></span><span class="s"><span class="k"><tt>
</tt> def r_</span><span class="il"><span class="dl">#{</span>meth<span class="dl">}</span></span><span class="k"><tt>
</tt> </span><span class="il"><span class="dl">#{</span>amount.is_a?(<span class="co">Array</span>) ? <span class="s"><span class="dl">"</span><span class="il"><span class="dl">#{</span>amount[<span class="i">0</span>]<span class="dl">}</span></span><span class="k">.</span><span class="il"><span class="dl">#{</span>amount[<span class="i">1</span>]<span class="dl">}</span></span><span class="dl">"</span></span> : <span class="s"><span class="dl">"</span><span class="il"><span class="dl">#{</span>amount<span class="dl">}</span></span><span class="dl">"</span></span><span class="dl">}</span></span><span class="k"><tt>
</tt> end<tt>
</tt> alias_method :r_</span><span class="il"><span class="dl">#{</span>meth<span class="dl">}</span></span><span class="k">s, :r_</span><span class="il"><span class="dl">#{</span>meth<span class="dl">}</span></span><span class="dl"><tt>
</tt> RUBY</span></span><tt>
</tt> <span class="r">end</span><tt>
</tt><tt>
</tt><span class="r">end</span><tt>
</tt><span class="co">Numeric</span>.send <span class="sy">:include</span>, <span class="co">RefaMetaTimeDSL</span><tt>
</tt>
</code></pre>
<p>the refactor 2 or eval based solution provided by <a href="http://pastie.caboo.se/191414">Matt Jones</a> which uses class_eval like the previous refactor.</p>
<pre><code>1<tt>
</tt>2<tt>
</tt>3<tt>
</tt>4<tt>
</tt><strong>5</strong><tt>
</tt>6<tt>
</tt>7<tt>
</tt>8<tt>
</tt>9<tt>
</tt><strong>10</strong><tt>
</tt>11<tt>
</tt>12<tt>
</tt>13<tt>
</tt>14<tt>
</tt><strong>15</strong><tt>
</tt>16<tt>
</tt>17<tt>
</tt>18<tt>
</tt>19<tt>
</tt>
<tt>
</tt> <span class="r">module</span> <span class="cl">EvalMetaTimeDSL</span><tt>
</tt> <span class="r">def</span> <span class="pc">self</span>.included(base)<tt>
</tt> base.class_eval <span class="r">do</span><tt>
</tt> [ [<span class="sy">:e_second</span>, <span class="i">1</span>], <tt>
</tt> [<span class="sy">:e_minute</span>, <span class="i">60</span>], <tt>
</tt> [<span class="sy">:e_hour</span>, <span class="i">3600</span>], <tt>
</tt> [<span class="sy">:e_day</span>, [<span class="i">24</span>,<span class="sy">:e_hours</span>]], <tt>
</tt> [<span class="sy">:e_week</span>, [<span class="i">7</span>,<span class="sy">:e_days</span>]], <tt>
</tt> [<span class="sy">:e_month</span>, [<span class="i">30</span>,<span class="sy">:e_days</span>]], <tt>
</tt> [<span class="sy">:e_year</span>, [<span class="fl">365.25</span>, <span class="sy">:e_days</span>]]].each <span class="r">do</span> |meth, amount|<tt>
</tt> amount = amount.is_a?(<span class="co">Array</span>) ? amount[<span class="i">0</span>].send(amount[<span class="i">1</span>]) : amount<tt>
</tt> eval <span class="s"><span class="dl">"</span><span class="k">def </span><span class="il"><span class="dl">#{</span>meth<span class="dl">}</span></span><span class="k">; self*</span><span class="il"><span class="dl">#{</span>amount<span class="dl">}</span></span><span class="k">; end</span><span class="dl">"</span></span><tt>
</tt> alias_method <span class="s"><span class="dl">"</span><span class="il"><span class="dl">#{</span>meth<span class="dl">}</span></span><span class="k">s</span><span class="dl">"</span></span>, meth<tt>
</tt> <span class="r">end</span><tt>
</tt> <span class="r">end</span><tt>
</tt> <span class="r">end</span><tt>
</tt> <span class="r">end</span><tt>
</tt> <span class="co">Numeric</span>.send <span class="sy">:include</span>, <span class="co">EvalMetaTimeDSL</span><tt>
</tt>
</code></pre>
<p>and finally, the "better metaprogramming" version:</p>
<pre><code>1<tt>
</tt>2<tt>
</tt>3<tt>
</tt>4<tt>
</tt><strong>5</strong><tt>
</tt>6<tt>
</tt>7<tt>
</tt>8<tt>
</tt>9<tt>
</tt><strong>10</strong><tt>
</tt>11<tt>
</tt>12<tt>
</tt>13<tt>
</tt>14<tt>
</tt><strong>15</strong><tt>
</tt>16<tt>
</tt>17<tt>
</tt>18<tt>
</tt>19<tt>
</tt><strong>20</strong><tt>
</tt>21<tt>
</tt>22<tt>
</tt>
<tt>
</tt> <span class="r">module</span> <span class="cl">GoodMetaTimeDSL</span><tt>
</tt><tt>
</tt> <span class="co">SECOND</span> = <span class="i">1</span><tt>
</tt> <span class="co">MINUTE</span> = <span class="co">SECOND</span> * <span class="i">60</span><tt>
</tt> <span class="co">HOUR</span> = <span class="co">MINUTE</span> * <span class="i">60</span><tt>
</tt> <span class="co">DAY</span> = <span class="co">HOUR</span> * <span class="i">24</span><tt>
</tt> <span class="co">WEEK</span> = <span class="co">DAY</span> * <span class="i">7</span><tt>
</tt> <span class="co">MONTH</span> = <span class="co">DAY</span> * <span class="i">30</span><tt>
</tt> <span class="co">YEAR</span> = <span class="co">DAY</span> * <span class="fl">364.25</span><tt>
</tt> <tt>
</tt> <span class="s"><span class="dl">%w[</span><span class="k">SECOND MINUTE HOUR DAY WEEK MONTH YEAR</span><span class="dl">]</span></span>.each <span class="r">do</span> |const_name|<tt>
</tt> meth = const_name.downcase<tt>
</tt> class_eval <span class="s"><span class="dl"><<-RUBY</span></span> <span class="s"><span class="k"><tt>
</tt> def g_</span><span class="il"><span class="dl">#{</span>meth<span class="dl">}</span></span><span class="k"> <tt>
</tt> self * </span><span class="il"><span class="dl">#{</span>const_name<span class="dl">}</span></span><span class="k"> <tt>
</tt> end <tt>
</tt> alias g_</span><span class="il"><span class="dl">#{</span>meth<span class="dl">}</span></span><span class="k">s g_</span><span class="il"><span class="dl">#{</span>meth<span class="dl">}</span></span><span class="k"> </span><span class="dl"><tt>
</tt> RUBY</span></span><tt>
</tt> <span class="r">end</span><tt>
</tt><span class="r">end</span><tt>
</tt><span class="co">Numeric</span>.send <span class="sy">:include</span>, <span class="co">GoodMetaTimeDSL</span><tt>
</tt>
</code></pre>
<p>Looking at the refactored version by Wycats, you can see he's right and the major issue with the original version was define_method. Using class_eval does make things almost as fast and even faster than the no metaprogramming version.</p>
<p>Interesting enough, the benchmarks show that some methods from the meta modules are faster than the ones from the no meta module. Overall, an optimized metaprogramming can be more or else as fast as a non meta code. Of course, with the new VMs coming up, things might change a little bit depending on the language implementation.</p>
<p><em>In conclusion, metaprogramming can be as fast as no metaprogramming but that won't help your code readability and maintainability, so make sure to only use this great trick when needed!</em></p>
<p>p.s: <a href="http://pastie.textmate.org/217071">here</a> is the benchmark file if you don't believe me ;)</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[News update]]></title>
<link href="http://matt.aimonetti.net/posts/2008/06/18/news-update/"/>
<updated>2008-06-18T01:40:00+02:00</updated>
<id>http://matt.aimonetti.net/posts/2008/06/18/news-update</id>
<content type="html"><![CDATA[<p>I realized I haven't updated this blog in a while. Here is a quick update on what's happened and on things to come:</p>
<ul>
<li><p><a href="http://en.oreilly.com/rails2008/public/content/home">RailsConf 08</a>. Great conference, probably my last Rails Conf though. I'll be in Orlando for <a href="http://rubyconf.org/">Ruby Conf 08</a> and I'll focus on 1 or 2 local conferences (probably <a href="http://mtnwestrubyconf.org/">mountain west</a> and another one).</p></li>
<li><p>MerbCamp 08 in San Diego this Fall organized by <a href="http://sdruby.com">SD Ruby</a>. Details are not finalized yet but <a href="http://yehudakatz.com/">Yehuda Katz</a> announced it during his Merb talk at RailsConf.</p></li>
<li><p>Moved this blog to a new <a href="http://joyent.com">Joyent accelerator</a> with git support and finally have the possibility to use Ambition! (planning on moving from Mephisto to <a href="http://crazycool.co.uk/2008/04/26/announcing-feather">Feather</a>)</p></li>
<li><p>Launched a client's Merb app and getting around 3 million hits/day. Merb is just awesome. (more info when the client's app gets out of beta)</p></li>
<li><p>I'll join <a href="http://railsenvy.com/">Gregg Pollack</a> from <a href="http://railsenvy.com/">http://railsenvy.com/</a> during <a href="http://qcon.infoq.com">Qcon</a> and take part in the <a href="http://qcon.infoq.com/sanfrancisco-2008/tracks/show_track.jsp?trackOID=172">Ruby for the Enterprise</a> track. <a href="http://qcon.infoq.com/sanfrancisco-2008/speaker/Matt+Aimonetti">My talk</a> will focus on Merb usage in real life.</p></li>
<li><p>Renamed my github username, new repo url: <a href="http://github.com/mattetti">http://github.com/mattetti</a> (sorry about that)</p></li>
</ul>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[Avoid using metaprogramming (seriously!)]]></title>
<link href="http://matt.aimonetti.net/posts/2008/05/04/avoid-using-metaprogramming/"/>
<updated>2008-05-04T08:29:00+02:00</updated>
<id>http://matt.aimonetti.net/posts/2008/05/04/avoid-using-metaprogramming</id>
<content type="html"><![CDATA[<p>Ruby is sexy, Ruby is cool and its metaprogramming potential offers some really cook features. However you might not realize that your cleverness is slowing down your code.</p>
<p>Today I was working on cleaning up merb_helper a Merb plugin that brings a lot of the stuff Rails developers are used to. In Merb we aim for speed and try to avoid magic.</p>
<p>merb_plugin didn't receive a lot of love from the main contributors but few features were added by different contributors and the code became hard to maintain.</p>
<p>Looking at the code I quickly found this bad boy:</p>
<p>(Old Merb Time DSL using metaprogramming)</p>
<pre><code>module MetaTimeDSL
{:second => 1,
:minute => 60,
:hour => 3600,
:day => [24,:hours],
:week => [7,:days],
:month => [30,:days],
:year => [364.25, :days]}.each do |meth, amount|
define_method "m_#{meth}" do
amount = amount.is_a?(Array) ? amount[0].send(amount[1]) : amount
self * amount
end
alias_method "m_#{meth}s".intern, "m_#{meth}"
end
end
Numeric.send :include, MetaTimeDSL
</code></pre>
<p>The above code looks awful to me and I decided to rewrite it a way I thought would be more efficient:</p>
<pre><code> module TimeDSL
def second
self * 1
end
alias_method :seconds, :second
def minute
self * 60
end
alias_method :minutes, :minute
def hour
self * 3600
end
alias_method :hours, :hour
def day
self * 86400
end
alias_method :days, :day
def week
self * 604800
end
alias_method :weeks, :week
def month
self * 2592000
end
alias_method :months, :month
def year
self * 31471200
end
alias_method :years, :year
end
Numeric.send :include, TimeDSL
</code></pre>
<p>To make sure I was right, I run the following benchmarks:</p>
<pre><code>require 'benchmark'
TIMES = (ARGV[0] || 100_000).to_i
Benchmark.bmbm do |x|
x.report("metaprogramming 360.seconds") do
TIMES.times do
360.m_seconds
end
end
x.report("no metaprogramming 360.hours") do
TIMES.times do
360.seconds
end
end
x.report("metaprogramming 360.minutes") do
TIMES.times do
360.m_minutes
end
end
x.report("no metaprogramming 360.minutes") do
TIMES.times do
360.minutes
end
end
x.report("metaprogramming 360.hours") do
TIMES.times do
360.m_hours
end
end
x.report("no metaprogramming 360.hours") do
TIMES.times do
360.hours
end
end
x.report("metaprogramming 360.days") do
TIMES.times do