-
Notifications
You must be signed in to change notification settings - Fork 0
/
atom.xml
779 lines (631 loc) · 81.2 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
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title><![CDATA[Musings of a Flatiron Ruby Student]]></title>
<link href="http://Ewarren7.github.io/atom.xml" rel="self"/>
<link href="http://Ewarren7.github.io/"/>
<updated>2014-09-25T09:43:56-04:00</updated>
<id>http://Ewarren7.github.io/</id>
<author>
<name><![CDATA[Edward Warren]]></name>
</author>
<generator uri="http://octopress.org/">Octopress</generator>
<entry>
<title type="html"><![CDATA[Allowing Temporary Anonymous Users]]></title>
<link href="http://Ewarren7.github.io/blog/2014/09/24/allowing-temporary-anonymous-user/"/>
<updated>2014-09-24T17:33:34-04:00</updated>
<id>http://Ewarren7.github.io/blog/2014/09/24/allowing-temporary-anonymous-user</id>
<content type="html"><![CDATA[<h1>Mixing in Temporary Anonymous Users with Omniauth</h1>
<p>On a site I made with some fellow students, world-view.today, we allowed users who logged in with Twitter to customize the site by adding in their own cities. The log in was created using omniauth 2 and basically followed the steps outlined in fellow classmate <a href="http://randallreedjr.com/blog/2014/07/15/logging-in-with-github-using-omniauth-in-your-rails-app/">Randall’s blog</a>, substituting twitter for github.</p>
<p>One of the improvements we really wanted to make was to allow non logged in users to add in cities, a task that was not as daunting as we anticipated.</p>
<h2>Our site before anonymous users</h2>
<p>Our cities controller would associate a new city with a user whenever a logged in user added a city.
Our user table simply stored the active recorded created <strong>user_id</strong>, <strong>created_at</strong>, <strong>updated_at</strong>, as well as <strong>name</strong>, <strong>provider</strong>, <strong>uid</strong>, and <strong>image</strong>. The provider column represented the provider used by omniauth, which in our case was always Twitter. The uid column was the unique id returned by the oath provider, twitter in our case, and the image was the Twitter profile image of the user.</p>
<p>A city_users join table kept the user city relationships.</p>
<p>Our site relies heavily on javascript and ajax calls so that it never has to load another page after the initial page load. Thus, our controllers would pass JSON objects, containing the cities objects, info on a users logged in status, uid’s of saved items, ect.., back to our front end javascript.</p>
<h2>Adding temporary anonymous users</h2>
<p>Searching Google for creating users just based on a temporary basis using omniauth didn’t yield any results so we set off to figure it out on our own.</p>
<p>We settled on using the <code>session_id</code> that rails automatically creates and stores in a cookie for any visitor on your site. This id string is unique for any given visitor and thus we used this session_id as the unique identifier to store in the user’s uid column.</p>
<p>The first step in implementing this logically fell with our cities controller which handled the task of adding new cities and associating them with the current user. (Technically probably best to move this functionality into the model) When a new city was passed to the cities controller Create method via an ajax post request, the first thing the method did was set an @user variable:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="vi">@user</span> <span class="o">=</span> <span class="no">User</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="n">session</span><span class="o">[</span><span class="ss">:user_id</span><span class="o">]</span><span class="p">)</span> <span class="k">if</span> <span class="n">session</span><span class="o">[</span><span class="ss">:user_id</span><span class="o">]</span>
</span></code></pre></td></tr></table></div></figure>
<p>The <code>session[:user_id]</code> was a variable the sessions controller would add to the session cookie after a successful twitter oauth negotiation, aka only logged in users would have it. This variable also corresponds to the <code>user_id</code> assigned to a user when it is created with active record.</p>
<p>The first step was to create the temp user when the controller received a new city and the current user was not logged in.</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">if</span> <span class="o">!</span><span class="vi">@user</span> <span class="c1">#create a temp user tied to session ID</span>
</span><span class='line'> <span class="vi">@user</span> <span class="o">=</span> <span class="no">User</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="nb">name</span><span class="p">:</span> <span class="s1">'Guest'</span><span class="p">,</span> <span class="ss">provider</span><span class="p">:</span> <span class="s1">'anon'</span><span class="p">,</span> <span class="ss">uid</span><span class="p">:</span> <span class="n">session</span><span class="o">[</span><span class="ss">:session_id</span><span class="o">]</span><span class="p">,</span> <span class="ss">image</span><span class="p">:</span> <span class="s1">'https://origin.ih.constantcontact.com/fs197/1110193228531/img/301.jpg?a=1115291249439'</span><span class="p">)</span>
</span><span class='line'> <span class="vi">@user</span><span class="o">.</span><span class="n">cities</span> <span class="o"><<</span> <span class="o">[</span><span class="no">City</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="mi">1</span><span class="p">),</span> <span class="no">City</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="mi">2</span><span class="p">),</span> <span class="no">City</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="mi">3</span><span class="p">),</span> <span class="no">City</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="mi">4</span><span class="p">),</span> <span class="no">City</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span><span class="o">]</span>
</span><span class='line'> <span class="n">session</span><span class="o">[</span><span class="ss">:user_id</span><span class="o">]</span> <span class="o">=</span> <span class="vi">@user</span><span class="o">.</span><span class="n">id</span>
</span><span class='line'><span class="k">end</span>
</span><span class='line'>
</span><span class='line'><span class="k">unless</span> <span class="vi">@user</span><span class="o">.</span><span class="n">cities</span><span class="o">.</span><span class="n">find_by</span><span class="p">(</span><span class="ss">lat</span><span class="p">:</span> <span class="n">city_params</span><span class="o">[</span><span class="ss">:lat</span><span class="o">]</span><span class="p">,</span> <span class="ss">lon</span><span class="p">:</span> <span class="n">city_params</span><span class="o">[</span><span class="ss">:lon</span><span class="o">]</span><span class="p">)</span>
</span><span class='line'> <span class="c1">#above checks if the user already has this city and rejects the addition if so</span>
</span><span class='line'> <span class="vi">@user</span><span class="o">.</span><span class="n">cities</span> <span class="o"><<</span> <span class="vi">@city</span> <span class="k">if</span> <span class="vi">@user</span>
</span><span class='line'>
</span><span class='line'> <span class="c1">#the below handles deleting a city, which is mostly beyond the scope of this post. </span>
</span><span class='line'> <span class="n">del_city_id</span> <span class="o">=</span> <span class="n">city_params</span><span class="o">[</span><span class="ss">:lastClock</span><span class="o">].</span><span class="n">to_i</span>
</span><span class='line'>
</span><span class='line'> <span class="no">CityUser</span><span class="o">.</span><span class="n">find_by</span><span class="p">(</span><span class="n">user_id</span><span class="p">:</span> <span class="vi">@user</span><span class="o">.</span><span class="n">id</span><span class="p">,</span> <span class="n">city_id</span><span class="p">:</span> <span class="n">del_city_id</span><span class="p">)</span><span class="o">.</span><span class="n">destroy</span> <span class="k">if</span> <span class="vi">@user</span>
</span><span class='line'> <span class="n">render</span> <span class="ss">json</span><span class="p">:</span> <span class="vi">@city</span>
</span><span class='line'><span class="k">else</span>
</span><span class='line'> <span class="n">render</span> <span class="ss">json</span><span class="p">:</span> <span class="s2">"this city already exists"</span><span class="o">.</span><span class="n">to_json</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>
<p>The user would immediately get shoveled in the 5 default cities, allowing them to be treated as a normal user that should always have exactly 5 cities. Whenever a new city is added, the last city is deleted and the new city is added as the first.</p>
<p>Also note we set provider to anon. This allowed us to know this was a temporary user account. We also added to this temp user’s session cookie the user_id variable that now corresponded to their user_id in our users’ table.</p>
<p>Overall this allowed us to treat temporary users that could be treated like a real user without having to change much code.</p>
<h2>When a temp user isn’t a real user</h2>
<p>There were some distinctions that we decided would be practical to keep. We didn’t want our temp user’s to be able to save content from within each of their cities and these temp users still needed the option to actually log in with twitter.</p>
<p>These distinctions actually fit within our code base pretty well. Basically we wanted to treat a temp user as not logged in except for purposes of tracking which cities they had.</p>
<p>Rails was keeping track of whether or not a user was logged in via a helper method in the application controller called logged_in?</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">helper_method</span> <span class="k">def</span> <span class="nf">logged_in?</span>
</span><span class='line'> <span class="o">!!</span><span class="n">current_user</span>
</span><span class='line'><span class="k">end</span>
</span><span class='line'>
</span><span class='line'><span class="n">helper_method</span> <span class="k">def</span> <span class="nf">current_user</span>
</span><span class='line'> <span class="vi">@current_user</span> <span class="o">||=</span> <span class="no">User</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="n">session</span><span class="o">[</span><span class="ss">:user_id</span><span class="o">]</span><span class="p">)</span> <span class="k">if</span> <span class="n">session</span><span class="o">[</span><span class="ss">:user_id</span><span class="o">]</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>
<p>We added a simple conditional check that made it so <code>logged_in?</code> would only return true if the provider did not equal anon in addition to their being a user_id var in the session.</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">helper_method</span> <span class="k">def</span> <span class="nf">logged_in?</span>
</span><span class='line'> <span class="o">!!</span><span class="n">current_user</span> <span class="o">&&</span> <span class="vi">@current_user</span><span class="o">.</span><span class="n">provider</span> <span class="o">!=</span> <span class="s2">"anon"</span>
</span><span class='line'> <span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>
<p>On the front end side we created a similar global variable called <code>loggedIn</code> that would get set and update as needed via ajax requests. The rails users controller sets the value of this variable based on checking the users logged in status.</p>
<p>This meant we had a temp user whose cities would persist, but for all other purposes they would be treated as logged out.</p>
<h2>Transitioning a temp user to a twitter authenticated user</h2>
<p>To make the user experience as seamless as possible we wanted to make it so that a temp user who customized their cities and then logged in to our site with their twitter account for the first time would be able to keep their cities.</p>
<p>To do this we modified the Sessions Controller’s Create method which we had originally made when implementing OmniAuth with Twitter. This route is called as the twitter oauth callback and thus is invoked right after someone authenticates with twitter.</p>
<p>We added the third nested <code>if</code> that checks to see if the session contains a <code>user_id</code>. This was a perfect test for finding temp users who then authenticate with twitter because only a temp user or a fully logged in user would have a session user_id; however, a user who is already logged in would never be routed to this create method, an oauth callback route.</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">def</span> <span class="nf">create</span>
</span><span class='line'> <span class="k">if</span> <span class="n">auth_hash</span><span class="o">.</span><span class="n">present?</span>
</span><span class='line'> <span class="k">if</span> <span class="o">!</span><span class="vi">@user</span> <span class="o">=</span> <span class="no">User</span><span class="o">.</span><span class="n">find_by_provider_and_uid</span><span class="p">(</span><span class="n">auth_hash</span><span class="o">[</span><span class="ss">:provider</span><span class="o">]</span><span class="p">,</span> <span class="n">auth_hash</span><span class="o">[</span><span class="ss">:uid</span><span class="o">]</span><span class="p">)</span> <span class="c1">#ie a new twitter auth user. </span>
</span><span class='line'> <span class="k">if</span> <span class="n">session</span><span class="o">[</span><span class="ss">:user_id</span><span class="o">]</span> <span class="c1">#ie if was a temp user & this is first time authing with twitter then replace their temp account uid, provider, name and image with this new auth hash info. </span>
</span><span class='line'> <span class="vi">@user</span> <span class="o">=</span> <span class="no">User</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="n">session</span><span class="o">[</span><span class="ss">:user_id</span><span class="o">]</span><span class="p">)</span>
</span><span class='line'> <span class="vi">@user</span><span class="o">.</span><span class="n">uid</span> <span class="o">=</span> <span class="n">auth_hash</span><span class="o">[</span><span class="ss">:uid</span><span class="o">]</span>
</span><span class='line'> <span class="vi">@user</span><span class="o">.</span><span class="n">provider</span> <span class="o">=</span> <span class="n">auth_hash</span><span class="o">[</span><span class="ss">:provider</span><span class="o">]</span>
</span><span class='line'> <span class="vi">@user</span><span class="o">.</span><span class="n">name</span> <span class="o">=</span> <span class="n">auth_hash</span><span class="o">[</span><span class="ss">:info</span><span class="o">][</span><span class="ss">:name</span><span class="o">]</span>
</span><span class='line'> <span class="vi">@user</span><span class="o">.</span><span class="n">image</span> <span class="o">=</span> <span class="n">auth_hash</span><span class="o">[</span><span class="ss">:info</span><span class="o">][</span><span class="ss">:image</span><span class="o">]</span>
</span><span class='line'> <span class="vi">@user</span><span class="o">.</span><span class="n">save</span>
</span><span class='line'> <span class="k">else</span>
</span><span class='line'> <span class="vi">@user</span> <span class="o">=</span> <span class="no">User</span><span class="o">.</span><span class="n">create_from_omniauth</span><span class="p">(</span><span class="n">auth_hash</span><span class="p">)</span>
</span><span class='line'> <span class="vi">@user</span><span class="o">.</span><span class="n">cities</span> <span class="o"><<</span> <span class="o">[</span><span class="no">City</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="mi">1</span><span class="p">),</span> <span class="no">City</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="mi">2</span><span class="p">),</span> <span class="no">City</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="mi">3</span><span class="p">),</span> <span class="no">City</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="mi">4</span><span class="p">),</span> <span class="no">City</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span><span class="o">]</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'>
</span><span class='line'> <span class="k">if</span> <span class="vi">@user</span>
</span><span class='line'> <span class="n">session</span><span class="o">[</span><span class="ss">:user_id</span><span class="o">]</span> <span class="o">=</span> <span class="vi">@user</span><span class="o">.</span><span class="n">id</span>
</span><span class='line'> <span class="n">redirect_to</span> <span class="n">root_url</span>
</span><span class='line'> <span class="k">else</span>
</span><span class='line'> <span class="n">redirect_to</span> <span class="n">root_url</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'> <span class="k">else</span>
</span><span class='line'> <span class="n">redirect_to</span> <span class="n">root_url</span><span class="p">,</span> <span class="ss">:notice</span> <span class="o">=></span> <span class="s2">"Please login via twitter"</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>
<p>This third nested <code>if</code> sets the @user variable to the temp user if it finds a session <code>user_id</code>. It then replaces the <code>uid</code> of that user with the twitter provided oauth uid and also replaces the <code>provider</code>, <code>name</code> and <code>image</code> provided by the twitter authentication. Effectively this converts the temp user to a twitter authenticated, persistent world-view user who retains the cities they selected as a temp user.</p>
<p>If a user has authenticated with twitter on our site before but they come back as an anonymous temp user, when they re-authenticate with twitter, their information from their temp account is not passed on to their previous user.</p>
<h1>A database full of temp users</h1>
<p>One slight draw back to our temp user approach is that our database fills up with temp users who will never be accessed after a temp users session cookie is lost or expires.</p>
<p>On solution to this is to create a cron job that periodically checks for users with provider anon who were created over 30 days ago and then purges them.</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[Getting Geolocation in Ruby / Sinatra]]></title>
<link href="http://Ewarren7.github.io/blog/2014/06/29/getting-geolocation-in-ruby-slash-sinatra/"/>
<updated>2014-06-29T17:44:34-04:00</updated>
<id>http://Ewarren7.github.io/blog/2014/06/29/getting-geolocation-in-ruby-slash-sinatra</id>
<content type="html"><![CDATA[<h1>Getting Location in Ruby</h1>
<p>It is now very common to determine a user’s location by using HTML5 Geolocation. Below, I’ll discuss how to pass this geolocation information to a Ruby Sinatra environment by using the post method and some JavaScript.</p>
<p>While the HTML5 geolocation is great, its not available if you are only operating in a command line interface (CLI). Thus, I’d like to first point out a way to get location when your ruby program is command line only.</p>
<h2>Location in CLI Only Environment</h2>
<p>This is a very simple way to get surprisingly accurate (at least in my few tests in NYC) location information using the IP of the computer running the Ruby app, Nokogiri web scraping, and one’s IP address.</p>
<p>You will need gem ‘nokogiri’ and to require ‘open-uri’</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">def</span> <span class="nf">location</span>
</span><span class='line'> <span class="n">page</span> <span class="o">=</span> <span class="s2">"http://freegeoip.net/json/"</span>
</span><span class='line'> <span class="n">doc</span> <span class="o">=</span> <span class="ss">Nokogiri</span><span class="p">:</span><span class="ss">:HTML</span><span class="p">(</span><span class="nb">open</span><span class="p">(</span><span class="n">page</span><span class="p">,</span> <span class="s1">'User-Agent'</span> <span class="o">=></span> <span class="s1">'ruby'</span><span class="p">))</span>
</span><span class='line'> <span class="n">loc</span> <span class="o">=</span> <span class="sr">/(latitude)(\":)(\d+.\d+)(,\"longitude\":)(-\d+.\d+)/</span><span class="o">.</span><span class="n">match</span><span class="p">(</span><span class="n">doc</span><span class="o">.</span><span class="n">text</span><span class="p">)</span>
</span><span class='line'> <span class="n">lat</span> <span class="o">=</span> <span class="n">loc</span><span class="o">[</span><span class="mi">3</span><span class="o">]</span>
</span><span class='line'> <span class="n">lon</span> <span class="o">=</span> <span class="n">loc</span><span class="o">[</span><span class="mi">5</span><span class="o">]</span>
</span><span class='line'> <span class="k">return</span> <span class="o">[</span><span class="n">lat</span><span class="p">,</span><span class="n">lon</span><span class="o">]</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>
<p>This will query the site <a href="http://freegeoip.net/json">http://freegeoip.net/json</a> which in turn determines your public IP address and matches it against a database. Nokogiri then scrapes this result and then I use a Ruby regex match object to parse out the latitude and a longitude. Finally I return an array containing latidue and longitude.</p>
<p>I found that <a href="http://freegeoip.net/json">http://freegeoip.net/json</a> was fairly accurate. There is a gem called geocoder that seems to use the same database but it seemed to do a lot more and required active record. When I created this, I already was using nokogiri in the project so this was an easy add on and just seemed simpler.</p>
<h2>Location using HTML5 in a Sinatra environment</h2>
<p>This describes how to use HTML5 Geolocation and javascript to send your longitude / latitude to the Sintra server using a http post request.</p>
<h3>Overview</h3>
<p>It starts by loading a page that says getting location and requests the user’s location from their browser. Once it has a location, it loads a google map on the page showing it. While loading the map, javascript also fills in 2 hidden form values, one for latitude and the other longitude.</p>
<p>The user then clicks the Submit Location button which will do a post request to the server at the address specified in the form’s action attribute. Sinatra can then grab lat and long from the parmas variable and render a new page using erb or preform a redirect.</p>
<p>I’ll note that there may be a better way to do the following but this method seemed good enough and was within the scope of my current knowledge.</p>
<h4>Step 1</h4>
<p>This methods assume you are running a Ruby Sintra web based frame work.</p>
<p>First, you would set a <code>get</code> controller for your page that will request the location from the user’s browser using html. I used by root index page for this.</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">get</span> <span class="s1">'/'</span> <span class="k">do</span>
</span><span class='line'> <span class="n">erb</span> <span class="ss">:location</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>
<h4>Step 2</h4>
<p>Next, you set up an ERB template that includes a hidden form. Once the user’s browser responds to the geolocation request, this hidden form will be filled by JavaScript with the user’s longitude and latitude.</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
<span class='line-number'>50</span>
<span class='line-number'>51</span>
<span class='line-number'>52</span>
<span class='line-number'>53</span>
<span class='line-number'>54</span>
<span class='line-number'>55</span>
<span class='line-number'>56</span>
<span class='line-number'>57</span>
<span class='line-number'>58</span>
<span class='line-number'>59</span>
<span class='line-number'>60</span>
<span class='line-number'>61</span>
<span class='line-number'>62</span>
<span class='line-number'>63</span>
<span class='line-number'>64</span>
<span class='line-number'>65</span>
<span class='line-number'>66</span>
<span class='line-number'>67</span>
<span class='line-number'>68</span>
<span class='line-number'>69</span>
<span class='line-number'>70</span>
<span class='line-number'>71</span>
</pre></td><td class='code'><pre><code class='java'><span class='line'><span class="o"><!</span><span class="n">DOCTYPE</span> <span class="n">html</span><span class="o">></span>
</span><span class='line'><span class="o"><</span><span class="n">html</span><span class="o">></span>
</span><span class='line'><span class="o"><</span><span class="n">body</span><span class="o">></span>
</span><span class='line'>
</span><span class='line'><span class="o"><</span><span class="n">p</span> <span class="n">id</span><span class="o">=</span><span class="s">"demo"</span><span class="o">></span><span class="n">Getting</span> <span class="n">your</span> <span class="n">location</span><span class="o">...</span> <span class="o"></</span><span class="n">p</span><span class="o">></span>
</span><span class='line'><span class="o"><</span><span class="n">div</span> <span class="n">id</span><span class="o">=</span><span class="s">"mapholder"</span><span class="o">></</span><span class="n">div</span><span class="o">></span>
</span><span class='line'>
</span><span class='line'><span class="o"><</span><span class="n">script</span> <span class="n">src</span><span class="o">=</span><span class="s">"http://maps.google.com/maps/api/js?sensor=false"</span><span class="o">></</span><span class="n">script</span><span class="o">></span>
</span><span class='line'>
</span><span class='line'><span class="o"><</span><span class="n">script</span><span class="o">></span>
</span><span class='line'><span class="n">getLocation</span><span class="o">();</span>
</span><span class='line'><span class="n">var</span> <span class="n">x</span> <span class="o">=</span> <span class="n">document</span><span class="o">.</span><span class="na">getElementById</span><span class="o">(</span><span class="s">"demo"</span><span class="o">);</span>
</span><span class='line'>
</span><span class='line'><span class="n">function</span> <span class="nf">getLocation</span><span class="o">()</span> <span class="o">{</span>
</span><span class='line'> <span class="k">if</span> <span class="o">(</span><span class="n">navigator</span><span class="o">.</span><span class="na">geolocation</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'> <span class="n">navigator</span><span class="o">.</span><span class="na">geolocation</span><span class="o">.</span><span class="na">getCurrentPosition</span><span class="o">(</span><span class="n">showPosition</span><span class="o">,</span><span class="n">showError</span><span class="o">);</span>
</span><span class='line'> <span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
</span><span class='line'> <span class="n">x</span><span class="o">.</span><span class="na">innerHTML</span> <span class="o">=</span> <span class="s">"Geolocation is not supported by this browser."</span><span class="o">;}</span>
</span><span class='line'><span class="o">}</span>
</span><span class='line'>
</span><span class='line'><span class="n">function</span> <span class="nf">showPosition</span><span class="o">(</span><span class="n">position</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'>
</span><span class='line'> <span class="n">lat</span> <span class="o">=</span> <span class="n">position</span><span class="o">.</span><span class="na">coords</span><span class="o">.</span><span class="na">latitude</span><span class="o">;</span>
</span><span class='line'> <span class="n">lon</span> <span class="o">=</span> <span class="n">position</span><span class="o">.</span><span class="na">coords</span><span class="o">.</span><span class="na">longitude</span><span class="o">;</span>
</span><span class='line'> <span class="n">document</span><span class="o">.</span><span class="na">getElementById</span><span class="o">(</span><span class="err">'</span><span class="n">lat</span><span class="err">'</span><span class="o">).</span><span class="na">value</span> <span class="o">=</span> <span class="n">lat</span><span class="o">;</span>
</span><span class='line'> <span class="n">document</span><span class="o">.</span><span class="na">getElementById</span><span class="o">(</span><span class="err">'</span><span class="n">lon</span><span class="err">'</span><span class="o">).</span><span class="na">value</span> <span class="o">=</span> <span class="n">lon</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'> <span class="n">latlon</span> <span class="o">=</span> <span class="k">new</span> <span class="n">google</span><span class="o">.</span><span class="na">maps</span><span class="o">.</span><span class="na">LatLng</span><span class="o">(</span><span class="n">lat</span><span class="o">,</span> <span class="n">lon</span><span class="o">)</span>
</span><span class='line'> <span class="n">mapholder</span> <span class="o">=</span> <span class="n">document</span><span class="o">.</span><span class="na">getElementById</span><span class="o">(</span><span class="err">'</span><span class="n">mapholder</span><span class="err">'</span><span class="o">)</span>
</span><span class='line'> <span class="n">mapholder</span><span class="o">.</span><span class="na">style</span><span class="o">.</span><span class="na">height</span><span class="o">=</span><span class="err">'</span><span class="mi">250</span><span class="n">px</span><span class="err">'</span><span class="o">;</span>
</span><span class='line'> <span class="n">mapholder</span><span class="o">.</span><span class="na">style</span><span class="o">.</span><span class="na">width</span><span class="o">=</span><span class="err">'</span><span class="mi">500</span><span class="n">px</span><span class="err">'</span><span class="o">;</span>
</span><span class='line'>
</span><span class='line'> <span class="n">var</span> <span class="n">myOptions</span><span class="o">={</span>
</span><span class='line'> <span class="nl">center:</span><span class="n">latlon</span><span class="o">,</span><span class="nl">zoom:</span><span class="mi">14</span><span class="o">,</span>
</span><span class='line'> <span class="nl">mapTypeId:</span><span class="n">google</span><span class="o">.</span><span class="na">maps</span><span class="o">.</span><span class="na">MapTypeId</span><span class="o">.</span><span class="na">ROADMAP</span><span class="o">,</span>
</span><span class='line'> <span class="nl">mapTypeControl:</span><span class="kc">false</span><span class="o">,</span>
</span><span class='line'> <span class="nl">navigationControlOptions:</span><span class="o">{</span><span class="nl">style:</span><span class="n">google</span><span class="o">.</span><span class="na">maps</span><span class="o">.</span><span class="na">NavigationControlStyle</span><span class="o">.</span><span class="na">SMALL</span><span class="o">}</span>
</span><span class='line'> <span class="o">}</span>
</span><span class='line'>
</span><span class='line'> <span class="n">var</span> <span class="n">map</span> <span class="o">=</span> <span class="k">new</span> <span class="n">google</span><span class="o">.</span><span class="na">maps</span><span class="o">.</span><span class="na">Map</span><span class="o">(</span><span class="n">document</span><span class="o">.</span><span class="na">getElementById</span><span class="o">(</span><span class="s">"mapholder"</span><span class="o">),</span><span class="n">myOptions</span><span class="o">);</span>
</span><span class='line'> <span class="n">var</span> <span class="n">marker</span> <span class="o">=</span> <span class="k">new</span> <span class="n">google</span><span class="o">.</span><span class="na">maps</span><span class="o">.</span><span class="na">Marker</span><span class="o">({</span><span class="nl">position:</span><span class="n">latlon</span><span class="o">,</span><span class="nl">map:</span><span class="n">map</span><span class="o">,</span><span class="nl">title:</span><span class="s">"You are here!"</span><span class="o">});</span>
</span><span class='line'>
</span><span class='line'>
</span><span class='line'><span class="o">}</span>
</span><span class='line'>
</span><span class='line'><span class="n">function</span> <span class="nf">showError</span><span class="o">(</span><span class="n">error</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'> <span class="k">switch</span><span class="o">(</span><span class="n">error</span><span class="o">.</span><span class="na">code</span><span class="o">)</span> <span class="o">{</span>
</span><span class='line'> <span class="k">case</span> <span class="n">error</span><span class="o">.</span><span class="na">PERMISSION_DENIED</span><span class="o">:</span>
</span><span class='line'> <span class="n">x</span><span class="o">.</span><span class="na">innerHTML</span> <span class="o">=</span> <span class="s">"User denied the request for Geolocation."</span>
</span><span class='line'> <span class="k">break</span><span class="o">;</span>
</span><span class='line'> <span class="k">case</span> <span class="n">error</span><span class="o">.</span><span class="na">POSITION_UNAVAILABLE</span><span class="o">:</span>
</span><span class='line'> <span class="n">x</span><span class="o">.</span><span class="na">innerHTML</span> <span class="o">=</span> <span class="s">"Location information is unavailable."</span>
</span><span class='line'> <span class="k">break</span><span class="o">;</span>
</span><span class='line'> <span class="k">case</span> <span class="n">error</span><span class="o">.</span><span class="na">TIMEOUT</span><span class="o">:</span>
</span><span class='line'> <span class="n">x</span><span class="o">.</span><span class="na">innerHTML</span> <span class="o">=</span> <span class="s">"The request to get user location timed out."</span>
</span><span class='line'> <span class="k">break</span><span class="o">;</span>
</span><span class='line'> <span class="k">case</span> <span class="n">error</span><span class="o">.</span><span class="na">UNKNOWN_ERROR</span><span class="o">:</span>
</span><span class='line'> <span class="n">x</span><span class="o">.</span><span class="na">innerHTML</span> <span class="o">=</span> <span class="s">"An unknown error occurred."</span>
</span><span class='line'> <span class="k">break</span><span class="o">;</span>
</span><span class='line'> <span class="o">}</span>
</span><span class='line'>
</span><span class='line'><span class="o">}</span>
</span><span class='line'><span class="o"></</span><span class="n">script</span><span class="o">></span>
</span><span class='line'><span class="o"><</span><span class="n">form</span> <span class="n">id</span><span class="o">=</span><span class="s">"myForm"</span> <span class="n">action</span><span class="o">=</span><span class="err">'</span><span class="o">/</span><span class="n">go</span><span class="err">'</span> <span class="n">method</span><span class="o">=</span><span class="s">"post"</span><span class="o">></span>
</span><span class='line'> <span class="o"><</span><span class="n">input</span> <span class="n">type</span><span class="o">=</span><span class="err">'</span><span class="n">hidden</span><span class="err">'</span> <span class="n">id</span><span class="o">=</span><span class="s">"lat"</span> <span class="n">name</span><span class="o">=</span><span class="err">'</span><span class="n">lat</span><span class="err">'</span> <span class="n">value</span><span class="o">=</span><span class="err">''</span> <span class="o">/></span>
</span><span class='line'> <span class="o"><</span><span class="n">input</span> <span class="n">type</span><span class="o">=</span><span class="err">'</span><span class="n">hidden</span><span class="err">'</span> <span class="n">id</span><span class="o">=</span><span class="s">"lon"</span> <span class="n">name</span><span class="o">=</span><span class="err">'</span><span class="n">lon</span><span class="err">'</span> <span class="n">value</span><span class="o">=</span><span class="err">''</span> <span class="o">/></span>
</span><span class='line'> <span class="o"><</span><span class="n">input</span> <span class="n">type</span><span class="o">=</span><span class="err">'</span><span class="n">submit</span><span class="err">'</span> <span class="n">name</span><span class="o">=</span><span class="err">'</span><span class="n">submit</span><span class="err">'</span> <span class="n">value</span><span class="o">=</span><span class="err">'</span><span class="n">Submit</span> <span class="n">Location</span><span class="err">'</span> <span class="o">/></span>
</span><span class='line'><span class="o"></</span><span class="n">form</span><span class="o">></span>
</span><span class='line'>
</span><span class='line'><span class="o"></</span><span class="n">body</span><span class="o">></span>
</span><span class='line'><span class="o"></</span><span class="n">html</span><span class="o">></span>
</span></code></pre></td></tr></table></div></figure>
<p>
In the <code>showPosition(position)</code> function above the following JavaScript code causes the hidden form at the bottom to be filled with the user’s longitude and latitude values.</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='java'><span class='line'><span class="n">document</span><span class="o">.</span><span class="na">getElementById</span><span class="o">(</span><span class="err">'</span><span class="n">lat</span><span class="err">'</span><span class="o">).</span><span class="na">value</span> <span class="o">=</span> <span class="n">lat</span><span class="o">;</span>
</span><span class='line'><span class="n">document</span><span class="o">.</span><span class="na">getElementById</span><span class="o">(</span><span class="err">'</span><span class="n">lon</span><span class="err">'</span><span class="o">).</span><span class="na">value</span> <span class="o">=</span> <span class="n">lon</span><span class="o">;</span>
</span></code></pre></td></tr></table></div></figure>
<h4>Step 3</h4>
<p>Setup up a post controller that receives the post request from the form submission.</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">post</span> <span class="s1">'/go'</span> <span class="k">do</span>
</span><span class='line'> <span class="vi">@lat</span> <span class="o">=</span> <span class="n">params</span><span class="o">[</span><span class="ss">:lat</span><span class="o">]</span>
</span><span class='line'> <span class="vi">@lon</span> <span class="o">=</span> <span class="n">params</span><span class="o">[</span><span class="ss">:lon</span><span class="o">]</span>
</span><span class='line'> <span class="n">erb</span> <span class="ss">:index</span>
</span><span class='line'>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>
<p>The parmas var is automatically passed to the post method in Sinatra and you can then extract the lat and lon by calling the symbol version of their names as they were labled in the form. You can then pass the location info to another method or make them directly available to the erb template.</p>
<h3>Using both HTML5 Geolocation with an IP based fallback</h3>
<p>You can use both the methods described above, reserving the IP based geolocation for situations in which HTML5 Geolocation fails. While you could probably do this with Javascript and error handling, I achieved this by passing the location to a Ruby class method. By checking if the lat or lon paramaters were nil, I was able to conditionally fall back to the IP based lookup.</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">set_location</span> <span class="p">(</span><span class="n">lat</span><span class="p">,</span><span class="n">lon</span><span class="p">)</span>
</span><span class='line'> <span class="k">if</span> <span class="n">lat</span><span class="o">.</span><span class="n">nil?</span><span class="o">||</span> <span class="n">lon</span><span class="o">.</span><span class="n">nil?</span> <span class="c1">#if html5 location isn't passed, revert to this method</span>
</span><span class='line'> <span class="n">page</span> <span class="o">=</span> <span class="s2">"http://freegeoip.net/json/"</span>
</span><span class='line'> <span class="n">doc</span> <span class="o">=</span> <span class="ss">Nokogiri</span><span class="p">:</span><span class="ss">:HTML</span><span class="p">(</span><span class="nb">open</span><span class="p">(</span><span class="n">page</span><span class="p">,</span> <span class="s1">'User-Agent'</span> <span class="o">=></span> <span class="s1">'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.153 Safari/537.36'</span><span class="p">))</span>
</span><span class='line'> <span class="n">loc</span> <span class="o">=</span> <span class="sr">/(latitude)(\":)(\d+.\d+)(,\"longitude\":)(-\d+.\d+)/</span><span class="o">.</span><span class="n">match</span><span class="p">(</span><span class="n">doc</span><span class="o">.</span><span class="n">text</span><span class="p">)</span>
</span><span class='line'> <span class="vi">@lat</span> <span class="o">=</span> <span class="n">loc</span><span class="o">[</span><span class="mi">3</span><span class="o">]</span>
</span><span class='line'> <span class="vi">@lon</span> <span class="o">=</span> <span class="n">loc</span><span class="o">[</span><span class="mi">5</span><span class="o">]</span>
</span><span class='line'> <span class="k">else</span>
</span><span class='line'> <span class="vi">@lat</span> <span class="o">=</span> <span class="n">lat</span>
</span><span class='line'> <span class="vi">@lon</span> <span class="o">=</span> <span class="n">lon</span>
</span><span class='line'> <span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>
<p><em>HTML5 Geolocation code based on <a href="http://www.w3schools.com/">http://www.w3schools.com/</a> templates</em></p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[The Shoveled Hash]]></title>
<link href="http://Ewarren7.github.io/blog/2014/06/15/the-shoveled-hash/"/>
<updated>2014-06-15T18:50:54-04:00</updated>
<id>http://Ewarren7.github.io/blog/2014/06/15/the-shoveled-hash</id>
<content type="html"><![CDATA[<h2>‘Where’s My Shovel’ asks the Hash</h2>
<p>As a typical Ruby student, I became acquainted with arrays before hashes. The array shovel, aka <code><<</code> really made sense to me and once I moved on to Hashes I found it very disconcerting that hashes were left shovelless.</p>
<p>Now that my studies have moved into classes and duck punching I decided I would try and give my hashes some shovels and see what became of it.</p>
<h2>A hash without a shovel</h2>
<p>If you ever attempted to use a shovel with a hash, the ruby interpreter greets you with:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="p">{</span><span class="ss">:a</span> <span class="o">=></span> <span class="s2">"one"</span><span class="p">,</span> <span class="ss">:b</span> <span class="o">=></span> <span class="s2">"two"</span><span class="p">,</span> <span class="ss">:c</span> <span class="o">=></span> <span class="s2">"three"</span><span class="p">}</span> <span class="o"><<</span> <span class="p">{</span><span class="ss">:d</span> <span class="o">=></span> <span class="s2">"three"</span><span class="p">}</span>
</span><span class='line'><span class="o">=></span><span class="ss">NoMethodError</span><span class="p">:</span> <span class="n">undefined</span> <span class="nb">method</span> <span class="sb">`<<' for {:a=>"one", :b=>"two", :c=>"three"}:Hash</span>
</span></code></pre></td></tr></table></div></figure>
<p>In the above scenario, the main ways to add the <code>{:d => "three"}</code> to the existing hash would be to use <code>merge!</code> or <code>store</code></p>
<p><code>merge!</code>:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="p">{</span><span class="ss">:a</span> <span class="o">=></span> <span class="s2">"one"</span><span class="p">,</span> <span class="ss">:b</span> <span class="o">=></span> <span class="s2">"two"</span><span class="p">,</span> <span class="ss">:c</span> <span class="o">=></span> <span class="s2">"three"</span><span class="p">}</span><span class="o">.</span><span class="n">merge!</span><span class="p">({</span><span class="ss">:d</span> <span class="o">=></span> <span class="s2">"three"</span><span class="p">})</span>
</span><span class='line'> <span class="o">=></span> <span class="p">{</span><span class="ss">:a</span><span class="o">=></span><span class="s2">"one"</span><span class="p">,</span> <span class="ss">:b</span><span class="o">=></span><span class="s2">"two"</span><span class="p">,</span> <span class="ss">:c</span><span class="o">=></span><span class="s2">"three"</span><span class="p">,</span> <span class="ss">:d</span><span class="o">=></span><span class="s2">"three"</span><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>
<p><code>store</code>:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="nb">test</span> <span class="o">=</span> <span class="p">{</span><span class="ss">:a</span> <span class="o">=></span> <span class="s2">"one"</span><span class="p">,</span> <span class="ss">:b</span> <span class="o">=></span> <span class="s2">"two"</span><span class="p">,</span> <span class="ss">:c</span> <span class="o">=></span> <span class="s2">"three"</span><span class="p">}</span>
</span><span class='line'> <span class="o">=></span> <span class="p">{</span><span class="ss">:a</span><span class="o">=></span><span class="s2">"one"</span><span class="p">,</span> <span class="ss">:b</span><span class="o">=></span><span class="s2">"two"</span><span class="p">,</span> <span class="ss">:c</span><span class="o">=></span><span class="s2">"three"</span><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="nb">test</span><span class="o">.</span><span class="n">store</span><span class="p">(</span><span class="ss">:d</span><span class="p">,</span> <span class="s2">"three"</span><span class="p">)</span>
</span><span class='line'> <span class="o">=></span> <span class="s2">"three"</span>
</span><span class='line'>
</span><span class='line'><span class="nb">test</span>
</span><span class='line'> <span class="o">=></span> <span class="p">{</span><span class="ss">:a</span><span class="o">=></span><span class="s2">"one"</span><span class="p">,</span> <span class="ss">:b</span><span class="o">=></span><span class="s2">"two"</span><span class="p">,</span> <span class="ss">:c</span><span class="o">=></span><span class="s2">"three"</span><span class="p">,</span> <span class="ss">:d</span><span class="o">=></span><span class="s2">"three"</span><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>
<p>Despite the verbosity of the above methods, they also have the affect of replacing a key’s value if you <code>merge!</code> or <code>store</code> using a key that already exists in the hash.</p>
<h2>A hash with a shovel is a beautiful thing</h2>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="p">{</span><span class="ss">:a</span> <span class="o">=></span> <span class="s2">"one"</span><span class="p">,</span> <span class="ss">:b</span> <span class="o">=></span> <span class="s2">"two"</span><span class="p">}</span> <span class="o"><<</span> <span class="p">{</span><span class="ss">:c</span> <span class="o">=></span> <span class="s2">"three"</span><span class="p">}</span>
</span><span class='line'><span class="o">=></span> <span class="p">{</span><span class="ss">:a</span><span class="o">=></span><span class="s2">"one"</span><span class="p">,</span> <span class="ss">:b</span><span class="o">=></span><span class="s2">"two"</span><span class="p">,</span> <span class="ss">:c</span><span class="o">=></span><span class="s2">"three"</span><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>
<p>The above seems so simple and elegant. Taking it further, what if the key you shovel already exists? Wouldn’t it be nice if the <code><<</code> method took the existing value in the hash and put it into an array and then added the passed values? I think so.</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="p">{</span><span class="ss">:a</span> <span class="o">=></span> <span class="s2">"one"</span><span class="p">,</span> <span class="ss">:b</span> <span class="o">=></span> <span class="s2">"two"</span><span class="p">}</span> <span class="o"><<</span> <span class="p">{</span><span class="ss">:b</span> <span class="o">=></span> <span class="s2">"an additional b value!!"</span><span class="p">}</span>
</span><span class='line'><span class="o">=></span> <span class="p">{</span><span class="ss">:a</span><span class="o">=></span><span class="s2">"one"</span><span class="p">,</span> <span class="ss">:b</span><span class="o">=>[</span><span class="s2">"two"</span><span class="p">,</span> <span class="s2">"an additional b value!!"</span><span class="o">]</span><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>
<p>What if the the key exists and it has a <strong>value that is already an array</strong>? Wouldn’t it be nice if the shoveled value was justed added to the array?</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="p">{</span><span class="ss">:a</span> <span class="o">=></span> <span class="s2">"one"</span><span class="p">,</span> <span class="ss">:b</span> <span class="o">=></span> <span class="o">[</span><span class="s2">"two"</span><span class="p">,</span> <span class="mi">2</span><span class="o">]</span><span class="p">}</span> <span class="o"><<</span> <span class="p">{</span><span class="ss">:b</span> <span class="o">=></span> <span class="s2">"an additional b value!!"</span><span class="p">}</span>
</span><span class='line'><span class="o">=></span> <span class="p">{</span><span class="ss">:a</span><span class="o">=></span><span class="s2">"one"</span><span class="p">,</span> <span class="ss">:b</span><span class="o">=>[</span><span class="s2">"two"</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="s2">"an additional b value!!"</span><span class="o">]</span><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>
<h3>Making the above a reality – duck punching the Hash class</h3>
<p>Achieving the above can be done by adding to / duck punching the Hash class. Defining a <code>class Hash</code> at the top of your ruby script is the simplest way to achieve this. The ruby interpretor will read from this version of the Hash class before looking up the main Hash class included with ruby. Any new methods added will exist in addition to the original Hash class methods.</p>
<h3>A very simple implementation</h3>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">class</span> <span class="nc">Hash</span>
</span><span class='line'> <span class="k">def</span> <span class="nf"><<</span><span class="p">(</span><span class="n">a</span><span class="p">)</span>
</span><span class='line'> <span class="nb">self</span><span class="o">.</span><span class="n">merge!</span><span class="p">(</span><span class="n">a</span><span class="p">)</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>
<p></p>
<p>With this simple class method added to Hash class you can now shovel an existing hash with another hash passed in the <code>{}</code> format.
The ruby interpreter allows you to do <code>hash1 << hash2</code> whereas most other methods would require the <code>.</code>, ie <code>hash1 << hash2</code> is the same as <code>hash1.<< hash2</code>. In the above the (a) is the passed parameter given after the <code><<</code></p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="p">{</span><span class="ss">:a</span> <span class="o">=></span> <span class="s2">"alpha"</span><span class="p">}</span> <span class="o"><<</span> <span class="p">{</span><span class="ss">:b</span> <span class="o">=></span> <span class="s2">"bravo"</span><span class="p">}</span>
</span><span class='line'> <span class="o">=></span> <span class="p">{</span><span class="ss">:a</span><span class="o">=></span><span class="s2">"alpha"</span><span class="p">,</span> <span class="ss">:b</span><span class="o">=></span><span class="s2">"bravo"</span><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>
<h3>Done with the baby steps</h3>
<p>While the above is great, the <code><<</code> method needs to grow a bit to give me the full functionality I described above (plus more!)
Below is my full Hash class duck punch, followed by some explanations.</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">class</span> <span class="nc">Hash</span>
</span><span class='line'> <span class="k">def</span> <span class="nf"><<</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="o">=</span><span class="kp">nil</span><span class="p">)</span>
</span><span class='line'> <span class="k">if</span> <span class="n">a</span><span class="o">.</span><span class="n">class</span> <span class="o">==</span> <span class="no">Hash</span>
</span><span class='line'> <span class="n">passed_key</span> <span class="o">=</span> <span class="n">a</span><span class="o">.</span><span class="n">first</span><span class="o">[</span><span class="mi">0</span><span class="o">]</span>
</span><span class='line'> <span class="n">passed_value</span> <span class="o">=</span> <span class="n">a</span><span class="o">.</span><span class="n">first</span><span class="o">[</span><span class="mi">1</span><span class="o">]</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'> <span class="k">if</span> <span class="n">a</span><span class="o">.</span><span class="n">class</span> <span class="o">==</span> <span class="nb">Array</span>
</span><span class='line'> <span class="n">passed_key</span> <span class="o">=</span> <span class="n">a</span><span class="o">[</span><span class="mi">0</span><span class="o">]</span>
</span><span class='line'> <span class="n">passed_value</span> <span class="o">=</span> <span class="n">a</span><span class="o">[</span><span class="mi">1</span><span class="o">.</span><span class="n">.</span><span class="o">-</span><span class="mi">1</span><span class="o">]</span> <span class="k">if</span> <span class="n">a</span><span class="o">.</span><span class="n">length</span> <span class="o">></span> <span class="mi">2</span> <span class="c1">#more than 2 values in passed array means pass_value becomes an array of all the values after [0]</span>
</span><span class='line'> <span class="n">passed_value</span> <span class="o">=</span> <span class="n">a</span><span class="o">[</span><span class="mi">1</span><span class="o">]</span> <span class="k">if</span> <span class="n">a</span><span class="o">.</span><span class="n">length</span> <span class="o">==</span> <span class="mi">2</span> <span class="c1"># only 2 values in array so first must be key and 2nd must be value</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'> <span class="k">if</span> <span class="o">!</span><span class="n">b</span><span class="o">.</span><span class="n">nil?</span> <span class="c1">#if a second argument is passed, treat it as first being the key and second being the value</span>
</span><span class='line'> <span class="n">passed_key</span><span class="o">=</span><span class="n">a</span>
</span><span class='line'> <span class="n">passed_value</span> <span class="o">=</span> <span class="n">b</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'>
</span><span class='line'> <span class="c1">#IMPLEMENTATION </span>
</span><span class='line'> <span class="k">if</span> <span class="nb">self</span><span class="o">[</span><span class="n">passed_key</span><span class="o">].</span><span class="n">nil?</span>
</span><span class='line'> <span class="nb">self</span><span class="o">.</span><span class="n">merge!</span><span class="p">({</span><span class="n">passed_key</span> <span class="o">=></span> <span class="n">passed_value</span><span class="p">})</span>
</span><span class='line'> <span class="k">else</span> <span class="c1">#if the key passed exists, then take current value of key and put it in array w/ passed valued</span>
</span><span class='line'> <span class="n">temp</span> <span class="o">=</span> <span class="nb">self</span><span class="o">[</span><span class="n">passed_key</span><span class="o">]</span> <span class="c1">#grab current value of existing key</span>
</span><span class='line'> <span class="k">if</span> <span class="n">temp</span><span class="o">.</span><span class="n">class</span> <span class="o">==</span> <span class="nb">Array</span> <span class="c1">#if the existing value is already an array then add to that array</span>
</span><span class='line'> <span class="nb">self</span><span class="o">[</span><span class="n">passed_key</span><span class="o">]</span> <span class="o"><<</span> <span class="n">passed_value</span>
</span><span class='line'> <span class="k">else</span>
</span><span class='line'> <span class="nb">self</span><span class="o">[</span><span class="n">passed_key</span><span class="o">]</span> <span class="o">=</span> <span class="o">[</span><span class="n">temp</span><span class="p">,</span><span class="n">passed_value</span><span class="o">]</span> <span class="c1">#create an array with original value and passed value</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'>
</span><span class='line'> <span class="k">return</span> <span class="nb">self</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'>
</span><span class='line'> <span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">array</span>
</span><span class='line'> <span class="no">Hash</span><span class="o">.</span><span class="n">new</span> <span class="p">{</span><span class="o">|</span><span class="nb">hash</span><span class="p">,</span> <span class="n">key</span><span class="o">|</span> <span class="nb">hash</span><span class="o">[</span><span class="n">key</span><span class="o">]</span> <span class="o">=</span> <span class="o">[]</span><span class="p">}</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>
<h5>The optional b parameter</h5>
<p>I added an optional parameter <code>b</code> which allows you to pass 2 parameters, the first being the key and the second being the value. Unfortunately, ruby does not let you use the space <code><<</code> shortcut explained above when passing two parameters. Instead, the only way to pass this second parameter (as far as I know) is using the <code>hash1.<< key,value</code>.</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="p">{</span><span class="ss">:a</span> <span class="o">=></span> <span class="s2">"one"</span><span class="p">,</span> <span class="ss">:b</span> <span class="o">=></span> <span class="s2">"two"</span><span class="p">}</span><span class="o">.</span><span class="n"><</span><span class="o"><</span> <span class="ss">:c</span><span class="p">,</span><span class="s2">"three"</span>
</span><span class='line'><span class="o">=></span> <span class="p">{</span><span class="ss">:a</span><span class="o">=></span><span class="s2">"one"</span><span class="p">,</span> <span class="ss">:b</span><span class="o">=></span><span class="s2">"two"</span><span class="p">,</span> <span class="ss">:c</span><span class="o">=></span><span class="s2">"three"</span><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>
<p>The rest of this new <code><<</code> method expects only one parameter, thus the space <code><<</code> space can be used.</p>
<h5>The conditional class checks at the top</h5>
<p>The initial if statements determine the class type of the parameter passed and break it into a key and a value assigned to <code>passed_key</code> and <code>passed_value</code> respectively.</p>
<p>The array method conditional allows you to pass a single parameter as an array containing a key with one or more values. The first element of the array will be treated as the key and the subsequent ones will be values. If there are multiple values passed they are kept in an array.</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="p">{</span><span class="ss">:a</span> <span class="o">=></span> <span class="s2">"one"</span><span class="p">,</span> <span class="ss">:b</span> <span class="o">=></span> <span class="s2">"two"</span><span class="p">}</span> <span class="o"><<</span> <span class="o">[</span><span class="ss">:c</span><span class="p">,</span> <span class="s2">"three"</span><span class="o">]</span>
</span><span class='line'><span class="o">=></span> <span class="p">{</span><span class="ss">:a</span><span class="o">=></span><span class="s2">"one"</span><span class="p">,</span> <span class="ss">:b</span><span class="o">=></span><span class="s2">"two"</span><span class="p">,</span> <span class="ss">:c</span><span class="o">=></span><span class="s2">"three"</span><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>
<h5>The implementation</h5>
<p>The first step under #IMPLEMENTATION is to see if the hash that is being added to already has a key with the same name as the key bing passed. When accessing a non existent hash key, the ruby interpreter will return nil. Thus if <code>self[passed_key].nil?</code> equals true, then the key does not exist in the original hash and a simple merge! can be used.</p>
<p>If the key does exist, then the existing value is put into an array and the passed value is added to that array. If the existing value is already an array then the passed value is added to the array.</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'> <span class="p">{</span><span class="ss">:a</span> <span class="o">=></span> <span class="s2">"one"</span><span class="p">,</span> <span class="ss">:b</span> <span class="o">=></span> <span class="s2">"two"</span><span class="p">,</span> <span class="ss">:c</span> <span class="o">=></span> <span class="o">[</span><span class="s2">"three"</span><span class="p">,</span> <span class="s2">"additional value"</span><span class="o">]</span><span class="p">}</span> <span class="o"><<</span> <span class="p">{</span><span class="ss">:c</span> <span class="o">=></span> <span class="s2">"a third value"</span><span class="p">}</span>
</span><span class='line'><span class="o">=></span> <span class="p">{</span><span class="ss">:a</span><span class="o">=></span><span class="s2">"one"</span><span class="p">,</span> <span class="ss">:b</span><span class="o">=></span><span class="s2">"two"</span><span class="p">,</span> <span class="ss">:c</span><span class="o">=>[</span><span class="s2">"three"</span><span class="p">,</span> <span class="s2">"additional value"</span><span class="p">,</span> <span class="s2">"a third value"</span><span class="o">]</span><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>
<h4>The final bit</h4>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">array</span>
</span><span class='line'> <span class="no">Hash</span><span class="o">.</span><span class="n">new</span> <span class="p">{</span><span class="o">|</span><span class="nb">hash</span><span class="p">,</span> <span class="n">key</span><span class="o">|</span> <span class="nb">hash</span><span class="o">[</span><span class="n">key</span><span class="o">]</span> <span class="o">=</span> <span class="o">[]</span><span class="p">}</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>
<p>This method is a little different from the main topic of the post. However, while I was ducking punching the hash class I figured I’d add in a simple but very useful functionality that also relates to the <code><<</code>. This functionality is based on fellow classmate <a href="http://pcrglennon.github.io/blog/2014/06/10/rubys-hash-dot-new-and-%7B%7D/">Peter’s blog post</a> regarding initializing a hash with empty array values.</p>
<p>Instead of having to type out <code>a = Hash.new {|hash, key| hash[key] = []}</code> I can just type <code>a = Hash.array</code>. Both of these initialize an empty hash with a default value of an empty array. This allows you to add to the hash by specifying a new or existing key and using a shovel to add to the array.</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">a</span> <span class="o">=</span> <span class="no">Hash</span><span class="o">.</span><span class="n">array</span>
</span><span class='line'><span class="o">=></span> <span class="p">{}</span>
</span><span class='line'>
</span><span class='line'><span class="n">a</span><span class="o">[</span><span class="ss">:new_key</span><span class="o">]</span> <span class="o"><<</span> <span class="s2">"Value to be added to value array"</span>
</span><span class='line'><span class="o">=></span> <span class="o">[</span><span class="s2">"Value to be added to value array"</span><span class="o">]</span>
</span><span class='line'>
</span><span class='line'><span class="n">a</span>
</span><span class='line'><span class="o">=></span> <span class="p">{</span><span class="ss">:new_key</span><span class="o">=>[</span><span class="s2">"Value to be added to value array"</span><span class="o">]</span><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>
<h2>Practicality</h2>
<p>It is admittedly not convenient to add this lengthy duck punch at the top of your scripts. You could put this code in a separate file and <code>include</code> it, but not only does every person running your ruby code also need the class modification, doing this may create confusion since it is not part of the normal ruby Hash class.</p>
<p>With that said, this new method does add functionality that comports with the style already used for <code><<</code> and arrays, thus giving a code reader contextual clues that strongly hint at the methods functionality. Additionally, it is my hope that this experiment provides a basis for the consideration and discussion of possibly seeing how a shovel could be introduced as an official method to the Hash class.</p>
<p><em>Tested using Ruby Version 2.1.2</em></p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[My First Post on Octopress]]></title>
<link href="http://Ewarren7.github.io/blog/2014/06/15/my-first-post-on-octopress/"/>
<updated>2014-06-15T14:04:10-04:00</updated>
<id>http://Ewarren7.github.io/blog/2014/06/15/my-first-post-on-octopress</id>
<content type="html"><![CDATA[<p>Hello, world!</p>
]]></content>
</entry>
</feed>