Help
RSS
API
Feed
Maltego
Contact
Domain > aaronkromer.com
×
Welcome!
Right click nodes and scroll the mouse to navigate the graph.
×
More information on this domain is in
AlienVault OTX
Is this malicious?
Yes
No
DNS Resolutions
Date
IP Address
2015-11-08
23.235.44.133
(
ClassC
)
2016-07-05
151.101.48.133
(
ClassC
)
2016-08-08
151.101.44.133
(
ClassC
)
2018-04-23
151.101.45.147
(
ClassC
)
2024-08-24
185.199.108.153
(
ClassC
)
Port 80
HTTP/1.1 301 Moved PermanentlyConnection: keep-aliveContent-Length: 162Server: GitHub.comContent-Type: text/htmlLocation: https://aaronkromer.com/X-GitHub-Request-Id: E89D:10CF:2003CEE:20CFF5B:66C96DBEAccept-Ranges: bytesAge: 0Date: Sat, 24 Aug 2024 05:21:02 GMTVia: 1.1 varnishX-Served-By: cache-bfi-kbfi7400095-BFIX-Cache: MISSX-Cache-Hits: 0X-Timer: S1724476863.563604,VS0,VE69Vary: Accept-EncodingX-Fastly-Request-ID: 632346d971e3f7765336bd2274ef0e735d2cc518 html>head>title>301 Moved Permanently/title>/head>body>center>h1>301 Moved Permanently/h1>/center>hr>center>nginx/center>/body>/html>
Port 443
HTTP/1.1 200 OKConnection: keep-aliveContent-Length: 77600Server: GitHub.comContent-Type: text/html; charsetutf-8Last-Modified: Fri, 25 May 2018 01:44:08 GMTAccess-Control-Allow-Origin: *ETag: 5b076a68-12f20expires: Sat, 24 Aug 2024 05:31:02 GMTCache-Control: max-age600x-proxy-cache: MISSX-GitHub-Request-Id: 84B6:1109:1290E8B:1305E8E:66C96DBDAccept-Ranges: bytesAge: 0Date: Sat, 24 Aug 2024 05:21:02 GMTVia: 1.1 varnishX-Served-By: cache-bfi-krnt7300109-BFIX-Cache: MISSX-Cache-Hits: 0X-Timer: S1724476863.688904,VS0,VE69Vary: Accept-EncodingX-Fastly-Request-ID: efec87d70350f4f688fc2cee7382718174b9cc4e !DOCTYPE HTML>html>head> meta charsetutf-8> title>Aaron Kromers Blog/title> meta nameauthor contentAaron Kromer> meta namedescription contentPublished on: Sep 29th, 2014 Tags: json, rspec, ruby In the past, testing JSON APIs tended to be a bit painful for me. Most of thispain revolved …> meta nameviewport contentwidthdevice-width, initial-scale1, maximum-scale1> link href/atom.xml relalternate titleAaron Kromers Blog typeapplication/atom+xml> link relcanonical href> link href/favicon.ico relshortcut icon> link href/stylesheets/screen.css mediascreen, projection relstylesheet typetext/css> link hrefhttp://fonts.googleapis.com/css?familySlackey relstylesheet typetext/css> link hrefhttp://fonts.googleapis.com/css?familyFjalla+One relstylesheet typetext/css> link hrefhttp://fonts.googleapis.com/css?familyAmethysta relstylesheet typetext/css> script src//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js>/script> !--if lt IE 9>script src//html5shiv.googlecode.com/svn/trunk/html5.js>/script>!endif--> script typetext/javascript src/javascripts/jquery-tapir.js>/script> !-- remove or comment it to disable ajaxification --> script src/javascripts/ajaxify.js>/script> script typetext/javascript> var _gaq _gaq || ; _gaq.push(_setAccount, UA-34364108-1); _gaq.push(_trackPageview); (function() { var ga document.createElement(script); ga.type text/javascript; ga.async true; ga.src (https: document.location.protocol ? https://ssl : http://www) + .google-analytics.com/ga.js; var s document.getElementsByTagName(script)0; s.parentNode.insertBefore(ga, s); })(); /script>/head>body> div idwrapper> header idheader classinner>!-- for more effects see _animate.scss -->hgroup idheaderbg> h1>a href/>Aaron Kromers Blog/a>/h1> h2>A little cupa Kromer with your code/h2> /hgroup>ul idsocial-links> !-- GitHub --> li> a hrefhttps://github.com/cupakromer titleGitHub> i classfoundicon-github>/i> /a> /li> !-- Twitter --> li> a hrefhttp://www.twitter.com/cupakromer titleTwitter> i classfoundicon-twitter>/i> /a> /li> li> a href/atom.xml> i classfoundicon-rss>/i> /a> /li>/ul>!-- use full url including index.html for navigation bar if you are using ajax -->ul idnav> li idajax>a href/index.html>Home/a>/li> li idajax>a href/blog/archives/index.html>Archives/a>/li> li> div iddark> form methodget action/search.html idsearch> input namequery typetext placeholderSearch... x-webkit-speech /> /form> /div> /li> /ul>/header>div idtoload>!-- begin toload --> div idcontent classinner> article classpost> h2 classtitle> a href/blog/2014-09-29-farewell-json-api-gems.html> Farewell JSON API Gems/a> /h2> div classentry-content> div classmeta> div classdate>Published on: time datetime2014-09-29T11:51:00-04:00 pubdate data-updatedtrue>Sep 29span>th/span>, 2014/time>/div> div classtags>Tags: a classcategory href/blog/categories/json/>json/a>, a classcategory href/blog/categories/rspec/>rspec/a>, a classcategory href/blog/categories/ruby/>ruby/a>/div> /div> p>In the past, testing JSON APIs tended to be a bit painful for me. Most of thispain revolved around setting expectations on the response body./p>p>If you treat the response as a raw string, attempting to use regularexpressions ends up being an exercise in how you handle frustration. While aJSON body is a string, it has structure. Using regular expressions for parsingthem is akin to using a hammer on a screw. It’ll get the job done, but it’s thewrong tool for the job./p>p>Ruby gives us a hrefhttp://ruby-doc.org/stdlib-2.1.3/libdoc/json/rdoc/JSON.html#method-i-parse>code>JSON.parse/code>/a>.Which will convert a valid JSON string into a more familiar object structure.Now comes the “fun” part of actually verifying that structure:/p>ul>li>Sometimes you only care about part of the response/li>li>Sometimes you care about validating the entire response/li>li>Sometimes the response is very complicated consisting of many smaller, morelogically meaningful, structures/li>li>Sometimes you only care about the general structure (e.g. this value must bea number, that value must be either an empty array or an array of strings,etc.)/li>/ul>p>It is possible to do all of these validations out of the box. In my experience,writing them tended to be tedious. Often the resulting code left something tobe desired in terms of readability. This was especially true when validating thegeneral response structure./p>p>I like to follow the “one expectation per spec” guideline. However, this leadto writing many small specs. Normally, this is perfectly fine and something Iadvocate you do. However, in terms of a JSON response, it means I need to havemore discipline to keep everything explicitly organized./p>p>Naturally in the Ruby community, many gems have sprouted up to help with thisproblem set. I’ve had a bit of success with some of those gems in the past.However, with the release of RSpec 3, a hrefhttp://myronmars.to/n/dev-blog/2014/01/new-in-rspec-3-composable-matchers>several newfeatures/a>have eliminated my need for these JSON gems./p>p>Expectations on a JSON response is a great fit for a hrefhttps://www.relishapp.com/rspec/rspec-expectations/v/3-0/docs/composing-matchers>composingmatchers/a>.When I need to logically group checking several options, the a hrefhttps://www.relishapp.com/rspec/rspec-expectations/v/3-0/docs/compound-expectations>compound matchers/a>are the perfect tool./p>p>Often people don’t realize that the matcher messages (i.e. code>exist/code>, code>be/code>, code>eq/code>,code>include/code>, etc) are just del>factories/del> helpers (a href#json-factory-helper1>seeendnotes/a>). They are just helper methods which createthe matcher object for you. That means, we can easily write our own using ourapp’s domain language./p>p>Let’s jump right into an example!/p>p>These examples are assuming a JSON structure like one of the ones listed on thea hrefhttp://jsonapi.org/format/#document-structure-compound-documents>jsonapi.org/a>site. Though I am assuming integer value are represented as numbers and notstrings, since that is valid JSON and more meaningful:/p>figure classcode>figcaption>span>‘spec/requests/api/kits_spec.rb’/span>/figcaption>div classhighlight>table>tr>td classgutter>pre classline-numbers>span classline-number>1/span>span classline-number>2/span>span classline-number>3/span>span classline-number>4/span>span classline-number>5/span>span classline-number>6/span>span classline-number>7/span>span classline-number>8/span>span classline-number>9/span>span classline-number>10/span>span classline-number>11/span>span classline-number>12/span>span classline-number>13/span>span classline-number>14/span>span classline-number>15/span>span classline-number>16/span>span classline-number>17/span>span classline-number>18/span>span classline-number>19/span>span classline-number>20/span>span classline-number>21/span>span classline-number>22/span>span classline-number>23/span>span classline-number>24/span>span classline-number>25/span>span classline-number>26/span>span classline-number>27/span>span classline-number>28/span>span classline-number>29/span>span classline-number>30/span>span classline-number>31/span>span classline-number>32/span>span classline-number>33/span>span classline-number>34/span>span classline-number>35/span>span classline-number>36/span>span classline-number>37/span>span classline-number>38/span>span classline-number>39/span>span classline-number>40/span>span classline-number>41/span>span classline-number>42/span>span classline-number>43/span>span classline-number>44/span>span classline-number>45/span>span classline-number>46/span>span classline-number>47/span>span classline-number>48/span>span classline-number>49/span>span classline-number>50/span>span classline-number>51/span>span classline-number>52/span>span classline-number>53/span>span classline-number>54/span>span classline-number>55/span>span classline-number>56/span>span classline-number>57/span>span classline-number>58/span>span classline-number>59/span>span classline-number>60/span>span classline-number>61/span>span classline-number>62/span>span classline-number>63/span>span classline-number>64/span>span classline-number>65/span>span classline-number>66/span>span classline-number>67/span>span classline-number>68/span>span classline-number>69/span>span classline-number>70/span>span classline-number>71/span>span classline-number>72/span>span classline-number>73/span>span classline-number>74/span>span classline-number>75/span>span classline-number>76/span>span classline-number>77/span>span classline-number>78/span>span classline-number>79/span>span classline-number>80/span>span classline-number>81/span>span classline-number>82/span>span classline-number>83/span>span classline-number>84/span>span classline-number>85/span>span classline-number>86/span>span classline-number>87/span>span classline-number>88/span>span classline-number>89/span>span classline-number>90/span>span classline-number>91/span>span classline-number>92/span>span classline-number>93/span>span classline-number>94/span>span classline-number>95/span>span classline-number>96/span>span classline-number>97/span>span classline-number>98/span>span classline-number>99/span>/pre>/td>td classcode>pre>code classruby>span classline>span classnb>require/span> span classs1>'rails_helper'/span>/span>span classline>span classc1># Use common JSON helpers such as: `json_response`, `be_an_empty`, `all_match`/span>/span>span classline>span classnb>require/span> span classs1>'support/json_api_helpers'/span>/span>span classline>/span>span classline>span classno>RSpec/span>span classo>./span>span classn>describe/span> span classs2>"/api/kits"/span>span classp>,/span> span classss>type/span>span classp>:/span> span classss>:request/span> span classk>do/span>/span>span classline> span classk>def/span> span classnf>be_kits_root_json/span>/span>span classline> span classn>be_kits_json/span>span classo>./span>span classn>and/span>span classp>(/span>/span>span classline> span classkp>include/span>span classp>(/span>/span>span classline> span classs1>'meta'/span> span classo>>/span> span classp>{/span>/span>span classline> span classs1>'first'/span> span classo>>/span> span classn>anything/span>span classp>,/span>/span>span classline> span classs1>'last'/span> span classo>>/span> span classn>anything/span>span classp>,/span>/span>span classline> span classs1>'current'/span> span classo>>/span> span classn>anything/span>span classp>,/span>/span>span classline> span classp>}/span>/span>span classline> span classp>)/span>/span>span classline> span classp>)/span>/span>span classline> span classk>end/span>/span>span classline>/span>span classline> span classk>def/span> span classnf>be_kits_json/span>/span>span classline> span classkp>include/span>span classp>(/span>/span>span classline> span classs1>'version'/span> span classo>>/span> span classs1>'1.0'/span>span classp>,/span>/span>span classline> span classs1>'links'/span> span classo>>/span> span classp>{/span>/span>span classline> span classs1>'kits.beacons'/span> span classo>>/span> span classs2>"/span>span classsi>#{/span>span classn>beacons_url/span>span classsi>}/span>span classs2>/{kits.beacons}"/span>span classp>,/span>/span>span classline> span classs1>'kits.overlays'/span> span classo>>/span> span classs2>"/span>span classsi>#{/span>span classn>overlays_url/span>span classsi>}/span>span classs2>/{kits.overlays}"/span>span classp>,/span>/span>span classline> span classs1>'beacons.attributes'/span> span classo>>/span> span classs2>"/span>span classsi>#{/span>span classn>beacon_attributes_url/span>span classsi>}/span>span classs2>/{beacons.attributes}"/span>span classp>,/span>/span>span classline> span classp>},/span>/span>span classline> span classs1>'kits'/span> span classo>>/span> span classn>be_an_empty/span>span classp>(/span>span classnb>Array/span>span classp>)/span>span classo>./span>span classn>or/span>span classp>(/span>/span>span classline> span classn>all_match/span>span classp>(/span>/span>span classline> span classs1>'id'/span> span classo>>/span> span classno>Fixnum/span>span classp>,/span>/span>span classline> span classs1>'name'/span> span classo>>/span> span classn>be_nil/span>span classo>./span>span classn>or/span>span classp>(/span>span classn>be_a/span> span classnb>String/span>span classp>),/span>/span>span classline> span classs1>'api_token'/span> span classo>>/span> span classnb>String/span>span classp>,/span>/span>span classline> span classs1>'account'/span> span classo>>/span> span classn>be_nil/span>span classo>./span>span classn>or/span>span classp>(/span>/span>span classline> span classn>match/span>span classp>(/span>/span>span classline> span classs1>'id'/span> span classo>>/span> span classno>Fixnum/span>span classp>,/span>/span>span classline> span classs1>'name'/span> span classo>>/span> span classn>be_nil/span>span classo>./span>span classn>or/span>span classp>(/span>span classn>be_a/span> span classnb>String/span>span classp>),/span>/span>span classline> span classp>)/span>/span>span classline> span classp>),/span>/span>span classline> span classs1>'links'/span> span classo>>/span> span classp>{/span>/span>span classline> span classs1>'self'/span> span classo>>/span> span classsr>/\A/span>span classsi>#{/span>span classn>kits_url/span>span classsi>}/span>span classsr>\/\d+\z//span>span classp>,/span>/span>span classline> span classs1>'beacons'/span> span classo>>/span> span classn>be_an_empty/span>span classp>(/span>span classnb>Array/span>span classp>)/span>span classo>./span>span classn>or/span>span classp>(/span>span classn>all/span> span classn>be_a/span> span classno>Fixnum/span>span classp>),/span>/span>span classline> span classs1>'overlays'/span> span classo>>/span> span classn>be_an_empty/span>span classp>(/span>span classnb>Array/span>span classp>)/span>span classo>./span>span classn>or/span>span classp>(/span>span classn>all/span> span classn>be_a/span> span classno>Fixnum/span>span classp>),/span>/span>span classline> span classp>},/span>/span>span classline> span classp>),/span>/span>span classline> span classp>),/span>/span>span classline> span classp>)/span>/span>span classline> span classk>end/span>/span>span classline>/span>span classline> span classk>def/span> span classnf>include_linked_resources/span>span classp>(/span>span classo>*/span>span classn>resources/span>span classp>)/span>/span>span classline> span classn>resource_maps/span> span classo>/span> span classn>resources/span>span classo>./span>span classn>each_with_object/span>span classp>({})/span> span classp>{/span> span classo>|/span>span classn>resource/span>span classp>,/span> span classn>mappings/span>span classo>|/span>/span>span classline> span classn>mappings/span>span classo>./span>span classn>store/span>span classp>(/span>span classn>resource/span>span classo>./span>span classn>to_s/span>span classp>,/span> span classn>be_an/span>span classp>(/span>span classnb>Array/span>span classp>))/span>/span>span classline> span classp>}/span>/span>span classline> span classkp>include/span>span classp>(/span>span classs1>'linked'/span> span classo>>/span> span classn>resource_maps/span>span classp>)/span>/span>span classline> span classk>end/span>/span>span classline>/span>span classline> span classn>context/span> span classs2>"a basic user"/span>span classp>,/span> span classs2>"with a kit having no beacons or maps"/span> span classk>do/span>/span>span classline> span classc1># Setup world state/span>/span>span classline>/span>span classline> span classn>describe/span> span classs2>"requesting the kits root"/span> span classk>do/span>/span>span classline> span classn>it/span> span classs2>"conforms to the expected JSON structure"/span> span classk>do/span>/span>span classline> span classn>get/span> span classn>kits_path/span>span classp>,/span> span classo>*/span>span classn>options/span>/span>span classline> span classn>expect/span>span classp>(/span>span classn>json_response/span>span classp>)/span>span classo>./span>span classn>to/span> span classn>be_kits_root_json/span>/span>span classline> span classk>end/span>/span>span classline>/span>span classline> span classc1># More specific specs/span>/span>span classline> span classk>end/span>/span>span classline>/span>span classline> span classn>describe/span> span classs2>"requesting a kit"/span> span classk>do/span>/span>span classline> span classn>it/span> span classs2>"conforms to the expected JSON structure"/span> span classk>do/span>/span>span classline> span classn>get/span> span classn>kit_path/span>span classp>(/span>span classn>kit/span>span classp>),/span> span classo>*/span>span classn>options/span>/span>span classline> span classn>expect/span>span classp>(/span>span classn>json_response/span>span classp>)/span>span classo>./span>span classn>to/span> span classn>be_kits_json/span>/span>span classline> span classk>end/span>/span>span classline>/span>span classline> span classc1># More specific specs/span>/span>span classline> span classk>end/span>/span>span classline> span classk>end/span>/span>span classline>/span>span classline> span classc1># More state specs/span>/span>span classline>/span>span classline> span classn>context/span> span classs2>"a developer user"/span>span classp>,/span> span classs2>"sending request with parameter 'include'"/span> span classk>do/span>/span>span classline> span classc1># Setup world state/span>/span>span classline>/span>span classline> span classn>describe/span> span classs2>"requesting the kits root"/span> span classk>do/span>/span>span classline> span classn>it/span> span classs2>"conforms to the expected JSON structure with included resources"/span> span classk>do/span>/span>span classline> span classn>get/span> span classn>kits_path/span>span classp>(/span>span classkp>include/span>span classp>:/span> span classs2>"beacons,beacon_attributes"/span>span classp>),/span> span classo>*/span>span classn>options/span>/span>span classline> span classn>expect/span>span classp>(/span>span classn>json_response/span>span classp>)/span>span classo>./span>span classn>to/span> span classn>be_kits_root_json/span>span classo>./span>span classn>and/span>span classp>(/span>/span>span classline> span classn>include_linked_resources/span>span classp>(/span>span classss>:beacons/span>span classp>,/span> span classss>:beacon_attributes/span>span classp>)/span>/span>span classline> span classp>)/span>/span>span classline> span classk>end/span>/span>span classline> span classk>end/span>/span>span classline>/span>span classline> span classn>describe/span> span classs2>"requesting a beacon"/span> span classk>do/span>/span>span classline> span classn>it/span> span classs2>"conforms to the expected JSON structure with included resources"/span> span classk>do/span>/span>span classline> span classn>get/span> span classn>kit_path/span>span classp>(/span>span classn>kit/span>span classp>,/span> span classkp>include/span>span classp>:/span> span classs2>"beacons,beacon_attributes"/span>span classp>),/span> span classo>*/span>span classn>options/span>/span>span classline> span classn>expect/span>span classp>(/span>span classn>json_response/span>span classp>)/span>span classo>./span>span classn>to/span> span classn>be_kits_json/span>span classo>./span>span classn>and/span>span classp>(/span>/span>span classline> span classn>include_linked_resources/span>span classp>(/span>span classss>:beacons/span>span classp>,/span> span classss>:beacon_attributes/span>span classp>)/span>/span>span classline> span classp>)/span>/span>span classline> span classk>end/span>/span>span classline> span classk>end/span>/span>span classline> span classk>end/span>/span>span classline>span classk>end/span>/span>/code>/pre>/td>/tr>/table>/div>/figure>p>The possibilities are fairly endless. We could improve this further by allowingthe factories to take model instances or attribute hashes. We can use those tocheck specific content when available:/p>figure classcode>figcaption>span>/span>/figcaption>div classhighlight>table>tr>td classgutter>pre classline-numbers>span classline-number>1/span>span classline-number>2/span>span classline-number>3/span>span classline-number>4/span>span classline-number>5/span>span classline-number>6/span>span classline-number>7/span>span classline-number>8/span>span classline-number>9/span>span classline-number>10/span>span classline-number>11/span>span classline-number>12/span>span classline-number>13/span>span classline-number>14/span>span classline-number>15/span>span classline-number>16/span>span classline-number>17/span>span classline-number>18/span>span classline-number>19/span>span classline-number>20/span>span classline-number>21/span>span classline-number>22/span>span classline-number>23/span>span classline-number>24/span>span classline-number>25/span>span classline-number>26/span>span classline-number>27/span>span classline-number>28/span>span classline-number>29/span>span classline-number>30/span>span classline-number>31/span>span classline-number>32/span>span classline-number>33/span>span classline-number>34/span>span classline-number>35/span>span classline-number>36/span>span classline-number>37/span>span classline-number>38/span>span classline-number>39/span>span classline-number>40/span>span classline-number>41/span>span classline-number>42/span>span classline-number>43/span>span classline-number>44/span>span classline-number>45/span>span classline-number>46/span>span classline-number>47/span>span classline-number>48/span>span classline-number>49/span>span classline-number>50/span>span classline-number>51/span>span classline-number>52/span>span classline-number>53/span>span classline-number>54/span>span classline-number>55/span>span classline-number>56/span>/pre>/td>td classcode>pre>code classruby>span classline>span classk>def/span> span classnf>account_resource/span>span classp>(/span>span classn>account/span> span classo>/span> span classkp>nil/span>span classp>,/span> span classn>allow_nil/span>span classp>:/span> span classkp>false/span>span classp>)/span>/span>span classline> span classk>return/span> span classkp>nil/span> span classk>unless/span> span classn>account/span> span classo>||/span> span classo>!/span>span classn>allow_nil/span>/span>span classline> span classk>if/span> span classn>account/span>/span>span classline> span classp>{/span>/span>span classline> span classs1>'id'/span> span classo>>/span> span classn>account/span>span classo>./span>span classn>id/span>span classp>,/span>/span>span classline> span classs1>'name'/span> span classo>>/span> span classn>account/span>span classo>./span>span classn>name/span>/span>span classline> span classp>}/span>/span>span classline> span classk>else/span>/span>span classline> span classp>{/span>/span>span classline> span classs1>'id'/span> span classo>>/span> span classno>Fixnum/span>span classp>,/span>/span>span classline> span classs1>'name'/span> span classo>>/span> span classn>be_nil/span>span classo>./span>span classn>or/span>span classp>(/span>span classn>be_a/span> span classnb>String/span>span classp>),/span>/span>span classline> span classp>}/span>/span>span classline> span classk>end/span>/span>span classline>span classk>end/span>/span>span classline>/span>span classline>span classk>def/span> span classnf>kit_resource/span>span classp>(/span>span classn>kit/span> span classo>/span> span classkp>nil/span>span classp>,/span> span classn>allow_nil/span>span classp>:/span> span classkp>false/span>span classp>)/span>/span>span classline> span classk>return/span> span classkp>nil/span> span classk>unless/span> span classn>kit/span> span classo>||/span> span classo>!/span>span classn>allow_nil/span>/span>span classline> span classk>if/span> span classn>kit/span>/span>span classline> span classp>{/span>/span>span classline> span classs1>'id'/span> span classo>>/span> span classn>kit/span>span classo>./span>span classn>id/span>span classp>,/span>/span>span classline> span classs1>'name'/span> span classo>>/span> span classn>kit/span>span classo>./span>span classn>name/span>span classp>,/span>/span>span classline> span classs1>'api_token'/span> span classo>>/span> span classn>kit/span>span classo>./span>span classn>api_token/span>span classp>,/span>/span>span classline> span classs1>'account'/span> span classo>>/span> span classn>account_resource/span>span classp>(/span>span classn>kit/span>span classo>./span>span classn>account/span>span classp>,/span> span classn>allow_nil/span>span classp>:/span> span classkp>true/span>span classp>),/span>/span>span classline> span classp>}/span>/span>span classline> span classk>else/span>/span>span classline> span classp>{/span>/span>span classline> span classs1>'id'/span> span classo>>/span> span classno>Fixnum/span>span classp>,/span>/span>span classline> span classs1>'name'/span> span classo>>/span> span classn>be_nil/span>span classo>./span>span classn>or/span>span classp>(/span>span classn>be_a/span> span classnb>String/span>span classp>),/span>/span>span classline> span classs1>'api_token'/span> span classo>>/span> span classnb>String/span>span classp>,/span>/span>span classline> span classs1>'account'/span> span classo>>/span> span classn>be_nil/span>span classo>./span>span classn>or/span>span classp>(/span>span classn>match/span> span classn>account_resource/span>span classp>),/span>/span>span classline> span classp>}/span>/span>span classline> span classk>end/span>/span>span classline>span classk>end/span>/span>span classline>/span>span classline>span classn>context/span> span classs2>"a basic user"/span>span classp>,/span> span classs2>"with a kit having no beacons or maps"/span> span classk>do/span>/span>span classline> span classc1># Setup world state/span>/span>span classline>/span>span classline> span classn>describe/span> span classs2>"requesting the kits root"/span> span classk>do/span>/span>span classline> span classn>it/span> span classs2>"conforms to the expected JSON structure"/span> span classk>do/span>/span>span classline> span classn>get/span> span classn>kits_path/span>span classp>,/span> span classo>*/span>span classn>options/span>/span>span classline> span classn>expect/span>span classp>(/span>span classn>json_response/span>span classp>)/span>span classo>./span>span classn>to/span> span classn>be_kits_root_json/span>/span>span classline> span classk>end/span>/span>span classline>/span>span classline> span classn>it/span> span classs2>"has only the expected kit"/span> span classk>do/span>/span>span classline> span classn>get/span> span classn>kits_path/span>span classp>,/span> span classo>*/span>span classn>options/span>/span>span classline> span classn>expect/span>span classp>(/span>span classn>json_response/span>span classp>)/span>span classo>./span>span classn>to/span> span classkp>include/span> span classs1>'kits'/span> span classo>>/span> span classo>/span>span classn>kit_resource/span>span classp>(/span>span classn>basic_users_kit/span>span classp>)/span>span classo>/span>/span>span classline> span classk>end/span>/span>span classline> span classk>end/span>/span>span classline>/span>span classline> span classn>describe/span> span classs2>"requesting a beacon"/span> span classk>do/span>/span>span classline> span classn>it/span> span classs2>"conforms to the expected JSON structure"/span> span classk>do/span>/span>span classline> span classn>get/span> span classn>kit_path/span>span classp>(/span>span classn>kit/span>span classp>),/span> span classo>*/span>span classn>options/span>/span>span classline> span classn>expect/span>span classp>(/span>span classn>json_response/span>span classp>)/span>span classo>./span>span classn>to/span> span classn>be_kits_json/span>span classp>(/span>span classn>basic_users_kit/span>span classp>)/span>/span>span classline> span classk>end/span>/span>span classline> span classk>end/span>/span>span classline>span classk>end/span>/span>/code>/pre>/td>/tr>/table>/div>/figure>p>Happy RSpec’ing!/p>h3>Updates 2014-09-30/h3>p>Thanks to everyone who provided feedback on this post. I’ve take it all intoconsideration and made the following changes:/p>ul>li>p>The first code sample now shows the full spec file structure. This hopefullymakes the important distinction that the helper methods are not being definedon code>main/code>./p>/li>li>p>The line code>require support/json_api_helpers/code> isn’t loading another library.Instead it is loading an extracted set of shared helper methods common tonearly all JSON API request specs for this project. These have been extractedto a module to keep them off of code>main/code> and placed in code>spec/support/code>./p>p>This follows the new guidance that specs should only load those files whichthey need. It also makes it easier for your future self and your co-workersto come back to the file later and try to find where things are defined./p>p>I’m including the file below for completeness:/p>/li>/ul>figure classcode>figcaption>span>/span>/figcaption>div classhighlight>table>tr>td classgutter>pre classline-numbers>span classline-number>1/span>span classline-number>2/span>span classline-number>3/span>span classline-number>4/span>span classline-number>5/span>span classline-number>6/span>span classline-number>7/span>span classline-number>8/span>span classline-number>9/span>span classline-number>10/span>span classline-number>11/span>span classline-number>12/span>span classline-number>13/span>span classline-number>14/span>span classline-number>15/span>span classline-number>16/span>span classline-number>17/span>span classline-number>18/span>span classline-number>19/span>span classline-number>20/span>span classline-number>21/span>span classline-number>22/span>span classline-number>23/span>span classline-number>24/span>/pre>/td>td classcode>pre>code classruby>span classline>span classc1># spec/support/json_api_helpers.rb/span>/span>span classline>span classk>module/span> span classnn>MyApp/span>/span>span classline> span classk>module/span> span classnn>RSpec/span>/span>span classline> span classk>module/span> span classnn>JsonApiHelpers/span>/span>span classline>/span>span classline> span classk>def/span> span classnf>json_response/span>/span>span classline> span classno>JSON/span>span classo>./span>span classn>parse/span> span classn>response/span>span classo>./span>span classn>body/span>/span>span classline> span classk>end/span>/span>span classline>/span>span classline> span classk>def/span> span classnf>be_an_empty/span>span classp>(/span>span classn>klass/span>span classp>)/span>/span>span classline> span classn>be_a/span>span classp>(/span>span classn>klass/span>span classp>)/span>span classo>./span>span classn>and/span>span classp>(/span>span classn>be_empty/span>span classp>)/span>/span>span classline> span classk>end/span>/span>span classline>/span>span classline> span classk>def/span> span classnf>all_match/span>span classp>(/span>span classo>*/span>span classn>args/span>span classp>)/span>/span>span classline> span classn>all/span> span classn>match/span>span classp>(/span>span classo>*/span>span classn>args/span>span classp>)/span>/span>span classline> span classk>end/span>/span>span classline>/span>span classline> span classk>end/span>/span>span classline> span classk>end/span>/span>span classline>span classk>end/span>/span>span classline>/span>span classline>span classno>RSpec/span>span classo>./span>span classn>configure/span> span classk>do/span> span classo>|/span>span classn>c/span>span classo>|/span>/span>span classline> span classn>c/span>span classo>./span>span classn>include/span> span classss>MyApp/span>span classp>:/span>span classss>:RSpec/span>span classo>::/span>span classno>JsonApiHelpers/span>span classp>,/span> span classss>type/span>span classp>:/span> span classss>:request/span>/span>span classline>span classk>end/span>/span>/code>/pre>/td>/tr>/table>/div>/figure>ul>li>p>It was pointed out that code>all match/code> will handle the empty code>Array/code> case.It is possible to amend the above code>be_an_empty(Array).or(all_match())/code>to instead read: code>be_an(Array).and(all_match())/code>./p>/li>li>p>a idjson-factory-helper1>/a>This is a helper method. My reference to itas a factory was more explicitly attempting to describe it as a helper methodwhich instantiates another object. In Rails, people often know of “factories”from the “factory vs fixture” debate. Often those factories are relativelysimple wrappers around constructors. After researching this a little more itseems in the larger programming world “factory” is not the proper term.Perhaps a hrefhttp://c2.com/cgi/wiki?CreationMethod>“creator”/a> is. I will move tocalling them helpers in the future./p>/li>/ul> /div>div classmeta> /div>/article> article classpost> h2 classtitle> a href/blog/2014-02-24-ignite-those-horrible-scripts.html> Ignite Those Horrible Scripts/a> /h2> div classentry-content> div classmeta> div classdate>Published on: time datetime2014-02-24T11:03:00-05:00 pubdate data-updatedtrue>Feb 24span>th/span>, 2014/time>/div> div classtags>Tags: a classcategory href/blog/categories/script/>script/a>, a classcategory href/blog/categories/shell/>shell/a>, a classcategory href/blog/categories/zsh/>zsh/a>/div> /div> p>The past week was spent dealing with an infuriating data crunching task.a hrefhttps://twitter.com/crsexton>Chris/a> and I decided to celebrate by killing ourpoorly written Ruby cli scripts with fire. Printing the scripts and going outback to set them on fire would be more dramatic. Though it probably would beappreciated by the other businesses which we share space with./p>p>I took a breather and looked into a hrefhttp://www.zsh.org/>zsh/a> functions toaccomplish this. Here’s what I came up with:/p>figure classcode>figcaption>span>/span>/figcaption>div classhighlight>table>tr>td classgutter>pre classline-numbers>span classline-number>1/span>span classline-number>2/span>span classline-number>3/span>span classline-number>4/span>span classline-number>5/span>span classline-number>6/span>span classline-number>7/span>span classline-number>8/span>span classline-number>9/span>span classline-number>10/span>span classline-number>11/span>span classline-number>12/span>span classline-number>13/span>span classline-number>14/span>span classline-number>15/span>span classline-number>16/span>span classline-number>17/span>span classline-number>18/span>span classline-number>19/span>span classline-number>20/span>span classline-number>21/span>span classline-number>22/span>span classline-number>23/span>span classline-number>24/span>span classline-number>25/span>span classline-number>26/span>span classline-number>27/span>span classline-number>28/span>span classline-number>29/span>span classline-number>30/span>span classline-number>31/span>span classline-number>32/span>span classline-number>33/span>span classline-number>34/span>span classline-number>35/span>span classline-number>36/span>span classline-number>37/span>span classline-number>38/span>span classline-number>39/span>span classline-number>40/span>span classline-number>41/span>span classline-number>42/span>span classline-number>43/span>span classline-number>44/span>span classline-number>45/span>span classline-number>46/span>span classline-number>47/span>span classline-number>48/span>/pre>/td>td classcode>pre>code classsh>span classline>rageflipspan classo>()/span> span classo>{/span> span classnb>echo/span> span classs2>" ┻━┻ ︵ヽ(\`Д´)ノ︵ ┻━┻ $*"/span> span classo>}/span>/span>span classline>/span>span classline>has_utilityspan classo>()/span> span classo>{/span> span classnb>hash/span> span classnv>$1/span> 2>/dev/null span classo>}/span>/span>span classline>/span>span classline>span classc># Wrapper around `rm -rf` expressing callers loathing and disdain for the/span>/span>span classline>span classc># provided files./span>/span>span classline>span classc>#/span>/span>span classline>span classc># Inspiration was Homebrew's output:/span>/span>span classline>span classc># 🍺 /usr/local/Cellar/tmux/1.9: 15 files, 628K, built in 25 seconds/span>/span>span classline>span classc>#/span>/span>span classline>span classc># For additional file stats, specific to code files, consider installing the/span>/span>span classline>span classc># Count Lines of Code (cloc) tool: http://cloc.sourceforge.net//span>/span>span classline>span classc>#/span>/span>span classline>span classc># brew install cloc/span>/span>span classline>span classc># sudo apt-get install cloc/span>/span>span classline>span classc>#/span>/span>span classline>ignitespan classo>()/span> span classo>{/span>/span>span classline> span classk>if/span> span classo>((/span> span classnv>$# /span>span classo>/span> 0 span classo>))/span> span classk>then /span>span classnb>echo/span> span classs2>"USAGE: ignite file file ..."/span>; span classk>return/span>; span classk>fi/span>/span>span classline>span classk> /span>span classnb>local /span>total_lines/span>span classline> span classnb>local /span>human_size/span>span classline> span classnb>local /span>lc_blank/span>span classline> span classnb>local /span>lc_comment/span>span classline> span classnb>local /span>lc_code/span>span classline> span classnb>echo/span> span classs2>"BURN IT ALL!!! $(rageflip)"/span>/span>span classline> span classk>for /span>i span classk>do/span>/span>span classline> span classc># If the file is empty we have 0 lines/span>/span>span classline> span classnv>human_size/span>span classo>/span>span classk>$(/span>ls -lh span classnv>$i/span> | awk span classs1>'{ print $5 }'/span>span classk>)/span>/span>span classline> span classnv>total_lines/span>span classo>/span>span classk>${$(/span>sed -n span classs1>'$'/span> span classnv>$i/span>span classk>):-/span>span classnv>0/span>span classk>}/span>/span>span classline> span classnv>stats/span>span classo>/span>span classs2>"$total_lines lines"/span>/span>span classline>/span>span classline> span classk>if /span>has_utility cloc; span classk>then/span>/span>span classline> span classc># Setup some local variables regarding file stats/span>/span>span classline> span classnv>lc_blank/span>span classo>/span>/span>span classline> span classnv>lc_comment/span>span classo>/span>/span>span classline> span classnv>lc_code/span>span classo>/span>/span>span classline> span classnb>eval/span> span classk>$(/span>/span>span classline> cloc span classnv>$i/span> --quiet | tail -2 | head -1 |/span>span classline> awk span classs1>'{ print "lc_blank"$3, "lc_comment"$4, "lc_code"$5 }'/span>/span>span classline> span classk>)/span>/span>span classline> span classk>if/span> span classo>/span> ! -z span classnv>$lc_blank/span> span classo>/span>; span classk>then/span>/span>span classline>span classk> /span>span classnv>stats/span>span classo>/span>span classs2>"$lc_code loc, $lc_comment comments, $lc_blank whitespace lines"/span>/span>span classline> span classk>fi/span>/span>span classline>span classk> fi/span>/span>span classline>/span>span classline>span classk> /span>rm -rf span classnv>$i/span>/span>span classline> span classnb>echo/span> span classs2>"🔥 $i: $stats, $human_size"/span>/span>span classline> span classk>done/span>/span>span classline>span classo>}/span>/span>/code>/pre>/td>/tr>/table>/div>/figure>p>Now we can sit back and watch it all burn:/p>figure classcode>figcaption>span>/span>/figcaption>div classhighlight>table>tr>td classgutter>pre classline-numbers>span classline-number>1/span>span classline-number>2/span>span classline-number>3/span>span classline-number>4/span>span classline-number>5/span>span classline-number>6/span>/pre>/td>td classcode>pre>code classsh>span classline>span classnv>$ /span>ignite script/crunch-*/span>span classline>BURN IT ALL!!! ┻━┻ ︵ヽspan classo>(/span>span classsb>`/span>Д´span classo>)/span>ノ︵ ┻━┻/span>span classline>🔥 script/crunch-dump-sessions: 5 loc, 5 comments, 2 whitespace lines, 330B/span>span classline>🔥 script/crunch-normalize: 47 loc, 14 comments, 11 whitespace lines, 2.2K/span>span classline>🔥 script/crunch-import-csv: 101 loc, 2 comments, 20 whitespace lines, 2.7K/span>span classline>🔥 script/crunch-timestamp: 203 loc, 44 comments, 38 whitespace lines, 8.4K/span>/code>/pre>/td>/tr>/table>/div>/figure>p>Though at this point, it might as well be a full script file. If I do that, Imight as well just write it as a Ruby cli…/p> /div>div classmeta> /div>/article> article classpost> h2 classtitle> a href/blog/2014-02-17-pitfalls-of-testing-scripts-with-load-part-2.html> Pitfalls of Testing Scripts With Load - Part 2/a> /h2> div classentry-content> div classmeta> div classdate>Published on: time datetime2014-02-17T10:15:00-05:00 pubdate data-updatedtrue>Feb 17span>th/span>, 2014/time>/div> div classtags>Tags: a classcategory href/blog/categories/ruby/>ruby/a>, a classcategory href/blog/categories/script/>script/a>, a classcategory href/blog/categories/testing/>testing/a>/div> /div> p>small>em>Check out the full Testing Scripts with Load series:a hrefhttp://aaronkromer.com/blog/2013-07-11-testing-scripts-with-load.html>part 1/a>,a hrefhttp://aaronkromer.com/blog/2013-07-29-pitfalls-of-testing-scripts-with-load-part-1.html>part 2/a>,a hrefhttp://aaronkromer.com/blog/2014-02-17-pitfalls-of-testing-scripts-with-load-part-2.html>part 3/a>/em>/small>/p>h2>Scope Smashing/h2>p>Take the following script and spec:/p>figure classcode>figcaption>span>/span>/figcaption>div classhighlight>table>tr>td classgutter>pre classline-numbers>span classline-number>1/span>span classline-number>2/span>span classline-number>3/span>span classline-number>4/span>span classline-number>5/span>/pre>/td>td classcode>pre>code classruby>span classline>span classc1>#!/usr/bin/env ruby/span>/span>span classline>/span>span classline>span classk>def/span> span classnf>current_user/span>/span>span classline> span classs1>'Bob'/span>/span>span classline>span classk>end/span>/span>/code>/pre>/td>/tr>/table>/div>/figure>figure classcode>figcaption>span>/span>/figcaption>div classhighlight>table>tr>td classgutter>pre classline-numbers>span classline-number>1/span>span classline-number>2/span>span classline-number>3/span>span classline-number>4/span>span classline-number>5/span>span classline-number>6/span>span classline-number>7/span>span classline-number>8/span>span classline-number>9/span>span classline-number>10/span>span classline-number>11/span>span classline-number>12/span>span classline-number>13/span>/pre>/td>td classcode>pre>code classruby>span classline>span classnb>require/span> span classs1>'spec_helper'/span>/span>span classline>/span>span classline>span classk>def/span> span classnf>current_user/span>/span>span classline> span classs1>'Alice'/span>/span>span classline>span classk>end/span>/span>span classline>/span>span classline>span classn>describe/span> span classs1>'Running the server locally'/span> span classk>do/span>/span>span classline> span classn>it/span> span classs1>'logs that it is running'/span> span classk>do/span>/span>span classline> span classnb>load/span> span classs1>'script/current-user-smash'/span>/span>span classline>/span>span classline> span classn>expect/span>span classp>(/span>span classn>current_user/span>span classp>)/span>span classo>./span>span classn>to/span> span classn>eq/span> span classs1>'Alice'/span>/span>span classline> span classk>end/span>/span>span classline>span classk>end/span>/span>/code>/pre>/td>/tr>/table>/div>/figure>p>Alas, the spec fails with:/p>figure classcode>figcaption>span>/span>/figcaption>div classhighlight>table>tr>td classgutter>pre classline-numbers>span classline-number>1/span>span classline-number>2/span>/pre>/td>td classcode>pre>code classruby>span classline>span classss>expected/span>span classp>:/span> span classs2>"Alice"/span>/span>span classline> span classss>got/span>span classp>:/span> span classs2>"Bob"/span>/span>/code>/pre>/td>/tr>/table>/div>/figure>p>This is due to how a hrefhttp://ruby-doc.org/core-2.1.0/Kernel.html#method-i-load>code>load/code>/a> works:/p>blockquote>p>If the optional code>wrap/code> parameter is code>true/code>, the loaded script will beexecuted under an anonymous module, protecting the calling program’s globalnamespace. In no circumstance will any local variables in the loaded file bepropagated to the loading environment./p>/blockquote>p>While it is easy to spot the issue this time, that’s not normally the case.Say if the additional method is define by a gem or in supporting file. Or ifyou are testing multiple scripts that each define the same top-level methods.These conditions will result in very strange and difficult to debug failures.Of course, it’s always a good idea to not define top-level methods to beginwith./p>p>Instead always pass the additional code>wrap/code> parameter. Here I’ve named it as adescriptive inline variable to reveal it’s intent:/p>figure classcode>figcaption>span>/span>/figcaption>div classhighlight>table>tr>td classgutter>pre classline-numbers>span classline-number>1/span>span classline-number>2/span>span classline-number>3/span>span classline-number>4/span>span classline-number>5/span>/pre>/td>td classcode>pre>code classruby>span classline>span classn>it/span> span classs1>'logs that it is running'/span> span classk>do/span>/span>span classline> span classnb>load/span> span classs1>'script/current-user-smash'/span>span classp>,/span> span classn>_in_sandbox/span> span classo>/span> span classkp>true/span>/span>span classline>/span>span classline> span classn>expect/span>span classp>(/span>span classn>current_user/span>span classp>)/span>span classo>./span>span classn>to/span> span classn>eq/span> span classs1>'Alice'/span>/span>span classline>span classk>end/span>/span>/code>/pre>/td>/tr>/table>/div>/figure> /div>div classmeta> /div>/article> article classpost> h2 classtitle> a href/blog/2014-02-06-open-classes-and-monkey-patching-at-retroruby.html> Discussion About Open Classes and Monkey Patching at #retroruby/a> /h2> div classentry-content> div classmeta> div classdate>Published on: time datetime2014-02-06T15:28:00-05:00 pubdate data-updatedtrue>Feb 6span>th/span>, 2014/time>/div> div classtags>Tags: a classcategory href/blog/categories/retroruby/>retroruby/a>, a classcategory href/blog/categories/ruby/>ruby/a>/div> /div> p>While at a hrefhttp://retroruby.org>RetroRuby 2014/a> a very good question was askedin the newbie track. The following code sample had just been shown on somebasic awesomeness of Ruby:/p>figure classcode>figcaption>span>/span>/figcaption>div classhighlight>table>tr>td classgutter>pre classline-numbers>span classline-number>1/span>span classline-number>2/span>/pre>/td>td classcode>pre>code classruby>span classline>span classs2>"Words"/span> span classo>*/span> span classmi>2/span>/span>span classline>span classc1># > "WordsWords"/span>/span>/code>/pre>/td>/tr>/table>/div>/figure>p>One of the participants then asked why that worked but the inverse didn’t:/p>figure classcode>figcaption>span>/span>/figcaption>div classhighlight>table>tr>td classgutter>pre classline-numbers>span classline-number>1/span>span classline-number>2/span>/pre>/td>td classcode>pre>code classruby>span classline>span classmi>2/span> span classo>*/span> span classs2>"Words"/span>/span>span classline>span classc1># TypeError: String can't be coerced into Fixnum/span>/span>/code>/pre>/td>/tr>/table>/div>/figure>h2>Oops what just happened?/h2>p>In Ruby, virtually everything is accomplished by sending a message to anotherobject. Above we would say:/p>blockquote>p>em>Send the message code>*/code> to code>Words/code> with parameter code>2/code>/em>/p>p>em>Send the message code>*/code> to code>2/code> with parameter code>Words/code>/em>/p>/blockquote>p>“Sending a message” is the Java equivalent of calling a method. Another way towrite the above is:/p>figure classcode>figcaption>span>/span>/figcaption>div classhighlight>table>tr>td classgutter>pre classline-numbers>span classline-number>1/span>span classline-number>2/span>/pre>/td>td classcode>pre>code classruby>span classline>span classs2>"Words"/span>span classo>./span>span classn>*/span>span classp>(/span>span classmi>2/span>span classp>)/span>/span>span classline>span classc1># > "WordsWords"/span>/span>/code>/pre>/td>/tr>/table>/div>/figure>p>Here we used the normal “method” calling syntax: code>obj.method(args)/code>/p>p>You’ll also probably see the following:/p>figure classcode>figcaption>span>/span>/figcaption>div classhighlight>table>tr>td classgutter>pre classline-numbers>span classline-number>1/span>span classline-number>2/span>/pre>/td>td classcode>pre>code classruby>span classline>span classs2>"Words"/span>span classo>./span>span classn>send/span>span classp>(/span>span classss>:*/span>span classp>,/span> span classmi>2/span>span classp>)/span>/span>span classline>span classc1># > "WordsWords"/span>/span>/code>/pre>/td>/tr>/table>/div>/figure>p>This time we explicitly sent the message: code>obj.send(message, args)/code>/p>p>With a hrefhttp://ruby-doc.org/core-2.1.0/Object.html#method-i-send>code>send/code>/a> Rubydoesn’t check if the message you passed was supposed to be public or private.Generally, what you wanted to do was dynamically send the message while stillmaking sure to respect the public API of the object. To do this you should usea hrefhttp://ruby-doc.org/core-2.1.0/Object.html#method-i-public_send>code>public_send/code>/a>instead: code>obj.public_send(message, args)/code>./p>p>So back to the original issue. Botha hrefhttp://ruby-doc.org/core-2.1.0/String.html>code>String/code>/a> anda hrefhttp://ruby-doc.org/core-2.1.0/Fixnum.html>code>Fixnum/code>/a> respond to the messagecode>*/code>./p>ul>li>a hrefhttp://ruby-doc.org/core-2.1.0/String.html#method-i-2A>code>String#*/code>/a>/li>li>a hrefhttp://ruby-doc.org/core-2.1.0/Fixnum.html#method-i-2A>code>Fixnum#*/code>/a>/li>/ul>p>However, code>String/code>’s implementation knows what to do when the argument is acode>Fixnum/code>. When we reverse it, the code>Fixnum/code> implementation doesn’t understandwhat to do with a code>String/code> argument./p>h2>How to fix this?/h2>p>Well you probably shouldn’t. But just for fun we’ll use Ruby’s open classbehavior to monkey patch code>Fixnum/code>’s code>*/code> implementation./p>figure classcode>figcaption>span>/span>/figcaption>div classhighlight>table>tr>td classgutter>pre classline-numbers>span classline-number>1/span>span classline-number>2/span>span classline-number>3/span>span classline-number>4/span>span classline-number>5/span>span classline-number>6/span>span classline-number>7/span>span classline-number>8/span>span classline-number>9/span>span classline-number>10/span>span classline-number>11/span>/pre>/td>td classcode>pre>code classruby>span classline>span classk>class/span> span classnc>Fixnum/span> span classc1># We just re-opened the class/span>/span>span classline>/span>span classline> span classk>def/span> span classnf>*/span>span classp>(/span>span classn>arg/span>span classp>)/span> span classc1># We're redefining the * message - this destroys the/span>/span>span classline> span classc1># previous implementation!!!/span>/span>span classline> span classn>arg/span> span classo>*/span> span classnb>self/span>/span>span classline> span classk>end/span>/span>span classline>/span>span classline>span classk>end/span>/span>span classline>/span>span classline>span classmi>2/span> span classo>*/span> span classs2>"Words"/span>/span>span classline>span classc1># > WordsWords/span>/span>/code>/pre>/td>/tr>/table>/div>/figure>p>It worked!! Before you go doing this to everything, be aware we’ve now lost theability to do normal multiplication. Additionally, we’ll overflow the stacktrying to multiply two code>Fixnum/code>s./p>figure classcode>figcaption>span>/span>/figcaption>div classhighlight>table>tr>td classgutter>pre classline-numbers>span classline-number>1/span>span classline-number>2/span>/pre>/td>td classcode>pre>code classruby>span classline>span classmi>2/span> span classo>*/span> span classmi>2/span>/span>span classline>span classc1># SystemStackError: stack level too deep/span>/span>/code>/pre>/td>/tr>/table>/div>/figure>h2>Wrap Up/h2>p>In Ruby, most things are messages sent from one object to another. Some timesthe language gives a little extra syntactic sugar to make sending the messagemore readable./p>p>Additionally, open classes and monkey patching have their uses. Just be awarethat with great power comes great responsibility. Always stop to ask yourselfif this is really a good idea; and try to never change existing behavior if youcan./p>h2>Level Up!/h2>p>So what if we just wanted to extend the existing functionality. There are alot of ways to do this and covering each, along with the pros and cons is veryout of scope for this post. I’m just going to demonstrate one way to illustratehow it could be done./p>p>You’ll need a new irb or Pry session so we get the original implementation forcode>Fixnum/code> back./p>figure classcode>figcaption>span>/span>/figcaption>div classhighlight>table>tr>td classgutter>pre classline-numbers>span classline-number>1/span>span classline-number>2/span>span classline-number>3/span>span classline-number>4/span>span classline-number>5/span>span classline-number>6/span>span classline-number>7/span>span classline-number>8/span>span classline-number>9/span>span classline-number>10/span>span classline-number>11/span>span classline-number>12/span>span classline-number>13/span>span classline-number>14/span>span classline-number>15/span>span classline-number>16/span>span classline-number>17/span>/pre>/td>td classcode>pre>code classruby>span classline>span classk>class/span> span classnc>Fixnum/span> span classc1># We just re-opened the class/span>/span>span classline>/span>span classline> span classc1># We need to store a reference to the original implementation One way to do/span>/span>span classline> span classc1># this is to create an alias for the original implementation so we can call/span>/span>span classline> span classc1># it later. Be sure to pick a descriptive name so that it isn't accidentally/span>/span>span classline> span classc1># overwritten by something else./span>/span>span classline> span classk>alias/span> span classss>:star_without_string_support/span> span classss>:*/span>/span>span classline>/span>span classline> span classk>def/span> span classnf>*/span>span classp>(/span>span classn>arg/span>span classp>)/span> span classc1># Redefine the message destroying the previous implementation!!!/span>/span>span classline> span classk>if/span> span classn>arg/span>span classo>./span>span classn>is_a?/span> span classnb>String/span>/span>span classline> span classn>arg/span> span classo>*/span> span classnb>self/span>/span>span classline> span classk>else/span>/span>span classline> span classn>star_without_string_support/span> span classn>arg/span> span classc1># use the original implementation/span>/span>span classline> span classk>end/span>/span>span classline> span classk>end/span>/span>span classline>/span>span classline>span classk>end/span>/span>/code>/pre>/td>/tr>/table>/div>/figure> /div>div classmeta> /div>/article> article classpost> h2 classtitle> a href/blog/2013-12-10-live-ing-dangerously-with-rails.html> Live-ing Dangerously With Rails/a> /h2> div classentry-content> div classmeta> div classdate>Published on: time datetime2013-12-10T13:08:00-05:00 pubdate data-updatedtrue>Dec 10span>th/span>, 2013/time>/div> div classtags>Tags: a classcategory href/blog/categories/rails/>rails/a>, a classcategory href/blog/categories/ruby/>ruby/a>/div> /div> p>Recently at work, we’ve been spinning up a bunch of demo apps on Heroku. Thishas worked out well for us so far. However, some of these apps requirebackground data crunching. This hasn’t been a problem as we just add a Raketask, or two, and set the Heroku scheduler to take care of things./p>p>Then comes the day when the sales team says:/p>blockquote>p>“Oh hey. Can we re-run all the numbers but with different configurations?”/p>/blockquote>p>Sure, that’s not a problem you think:/p>figure classcode>figcaption>span>/span>/figcaption>div classhighlight>table>tr>td classgutter>pre classline-numbers>span classline-number>1/span>/pre>/td>td classcode>pre>code classbash>span classline>span classnv>$ /span>heroku run rake redo_all_the_thingsspan classo>/span>config.ymlspan classo>/span>/span>/code>/pre>/td>/tr>/table>/div>/figure>p>However, there’s a few issues with this:/p>ol>li>The code>config.yml/code> needs to be on Heroku/li>li>This counts against your active dyno time/li>/ol>p>See the thing is, Heroku a hrefhttps://devcenter.heroku.com/articles/read-only-filesystem>doesn’t let you create files/a>that aren’t already in your VC system from outside the app. It’s nowa hrefhttps://devcenter.heroku.com/articles/dynos#ephemeral-filesystem>sorta possible on Cedar/a>,but not really for this purpose./p>p>Additionally, if these tasks turn out to be long running, that’ll quickly eatup the overhead on the ‘free’ dyno. For demo apps of non-paying customersthat’s not always an option./p>p>Enter the code>live/code> environment./p>p>Just add a new code>live/code> environment to the Rails application. This allows us torun Rake locally, but against the production database. Additionally, allowingfor custom configuration files to just be stored on our local system. And wedon’t spin up a new dyno on Heroku. Win, win!/p>p>To set this up:/p>ul>li>Update the code>Gemfile/code>/li>/ul>figure classcode>figcaption>span>/span>/figcaption>div classhighlight>table>tr>td classgutter>pre classline-numbers>span classline-number>1/span>span classline-number>2/span>span classline-number>3/span>span classline-number>4/span>span classline-number>5/span>/pre>/td>td classcode>pre>code classruby>span classline>span classc1># Gemfile/span>/span>span classline>/span>span classline>span classc1># We use dotenv-rails to help manage environment configs locally./span>/span>span classline>span classc1># Add our new environment:/span>/span>span classline>span classn>gem/span> span classs1>'dotenv-rails'/span>span classp>,/span> span classss>groups/span>span classp>:/span> span classo>/span>span classss>:development/span>span classp>,/span> span classss>:test/span>span classp>,/span> span classss>:live/span>span classo>/span>/span>/code>/pre>/td>/tr>/table>/div>/figure>ul>li>Add the live specific sample file: code>.env.live-example/code>/li>/ul>figure classcode>figcaption>span>/span>/figcaption>div classhighlight>table>tr>td classgutter>pre classline-numbers>span classline-number>1/span>span classline-number>2/span>span classline-number>3/span>span classline-number>4/span>span classline-number>5/span>span classline-number>6/span>span classline-number>7/span>span classline-number>8/span>span classline-number>9/span>span classline-number>10/span>span classline-number>11/span>span classline-number>12/span>span classline-number>13/span>span classline-number>14/span>span classline-number>15/span>span classline-number>16/span>/pre>/td>td classcode>pre>code classruby>span classline>span classc1># .env.live-example/span>/span>span classline>/span>span classline>span classc1># Rename this file to `.env.live` and it will be automatically sourced by/span>/span>span classline>span classc1># rails. Uncomment the settings for them to be picked up./span>/span>span classline>span classc1>#/span>/span>span classline>span classc1># Grab the settings from the output of:/span>/span>span classline>span classc1>#/span>/span>span classline>span classc1># $ heroku config/span>/span>span classline>span classc1>#/span>/span>span classline>span classc1># Running against the Heroku production DB directly/span>/span>span classline>span classc1># BE CAREFUL!! YOU HAVE BEEN WARNED!!/span>/span>span classline>span classc1>#DATABASE_NAMEWARNING/span>/span>span classline>span classc1>#DATABASE_HOSTDANGER/span>/span>span classline>span classc1>#DATABASE_PORTWILL/span>/span>span classline>span classc1>#DATABASE_USERROBINSON/span>/span>span classline>span classc1>#DATABASE_PASSWORDSERIOUSLY/span>/span>/code>/pre>/td>/tr>/table>/div>/figure>ul>li>Update the code>database.yml/code> file/li>/ul>figure classcode>figcaption>span>/span>/figcaption>div classhighlight>table>tr>td classgutter>pre classline-numbers>span classline-number>1/span>span classline-number>2/span>span classline-number>3/span>span classline-number>4/span>span classline-number>5/span>span classline-number>6/span>span classline-number>7/span>span classline-number>8/span>span classline-number>9/span>span classline-number>10/span>/pre>/td>td classcode>pre>code classyaml>span classline>span classc1># config/database.yml/span>/span>span classline>/span>span classline>span classl-Scalar-Plain>live/span>span classp-Indicator>:/span>/span>span classline> span classl-Scalar-Plain>adapter/span>span classp-Indicator>:/span> span classl-Scalar-Plain>postgresql/span>/span>span classline> span classl-Scalar-Plain>encoding/span>span classp-Indicator>:/span> span classl-Scalar-Plain>unicode/span>/span>span classline> span classl-Scalar-Plain>database/span>span classp-Indicator>:/span> span classl-Scalar-Plain><% ENV'DATABASE_NAME' %>/span>/span>span classline> span classl-Scalar-Plain>host/span>span classp-Indicator>:/span> span classl-Scalar-Plain><% ENV'DATABASE_HOST' %>/span>/span>span classline> span classl-Scalar-Plain>port/span>span classp-Indicator>:/span> span classl-Scalar-Plain><% ENV'DATABASE_PORT' %>/span>/span>span classline> span classl-Scalar-Plain>username/span>span classp-Indicator>:/span> span classl-Scalar-Plain><% ENV'DATABASE_USER' %>/span>/span>span classline> span classl-Scalar-Plain>password/span>span classp-Indicator>:/span> span classl-Scalar-Plain><% ENV'DATABASE_PASSWORD' %>/span>/span>/code>/pre>/td>/tr>/table>/div>/figure>ul>li>Copy code>config/environments/production.rb/code> to code>config/environments/live.rb/code>.If you wish to symlink it instead a hrefhttp://stackoverflow.com/questions/954560/what-does-git-do-to-files-that-are-a-symbolic-link>be wary of how git treats that/a>./li>/ul>p>Now running our tasks is as simple as:/p>figure classcode>figcaption>span>/span>/figcaption>div classhighlight>table>tr>td classgutter>pre classline-numbers>span classline-number>1/span>/pre>/td>td classcode>pre>code classbash>span classline>span classnv>$ RAILS_ENV/span>span classo>/span>live rake redo_all_the_thingsspan classo>/span>config-fun-edition.ymlspan classo>/span>/span>/code>/pre>/td>/tr>/table>/div>/figure> /div>div classmeta> /div>/article>nav idpagenavi> a href/blog/page/2/ classnext>Next/a> div classcenter>a href/blog/archives>Blog Archives/a>/div>/nav> /div> footer idfooter> div styledisplay:inline> p> Copyright © 2014 Aaron Kromer. All content on this site is available under a a hrefhttp://creativecommons.org/publicdomain/zero/1.0/>CC0 license/a>. /p> p> Powered by a hrefhttp://octopress.org>Octopress/a> | Theme based on a hrefhttp://github.com/panks/fabric>fabric/a> by a hrefhttp://panks.me>Pankaj Kumar/a> /p>/div> /footer> script src/javascripts/fabric.js>/script>script src/javascripts/jquery.fancybox.pack.js>/script>script typetext/javascript>(function($){ $(.fancybox).fancybox();})(jQuery);/script> !-- Delete or comment this line to disable Fancybox -->!-- end toload --> /div>/div>script src/javascripts/jquery.ui.totop.js typetext/javascript>/script>script typetext/javascript>/*!CDATA*/;(function($){$().UItoTop({easingType:easeOutCirc});})(jQuery); /*>*//script>!-- remove it to remove the scroll to top button -->/body>/html>
View on OTX
|
View on ThreatMiner
Please enable JavaScript to view the
comments powered by Disqus.
Data with thanks to
AlienVault OTX
,
VirusTotal
,
Malwr
and
others
. [
Sitemap
]