{"id":1701,"date":"2026-09-24T10:48:08","date_gmt":"2026-09-24T09:48:08","guid":{"rendered":"https:\/\/ruby-doc.org\/learn\/?p=1701"},"modified":"2026-09-24T10:48:09","modified_gmt":"2026-09-24T09:48:09","slug":"building-an-editors-research-reading-list-with-ruby","status":"publish","type":"post","link":"https:\/\/ruby-doc.org\/learn\/building-an-editors-research-reading-list-with-ruby\/","title":{"rendered":"Building an Editor\u2019s Research Reading List With Ruby"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Saving a link takes a moment. Recalling why you saved it can take considerably longer.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">You see a headline, so you keep the tab open. A few days later, dozens of tabs are in front of you and the detail you needed to verify is gone from memory. You have access to the source. You have lost sight of the reason to keep it.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A simple Ruby application can help solve this. The purpose of the application is to store an editor\u2019s notes along with each source, identify duplicate links and create a page to open when research resumes.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Here is a step-by-step process to develop the first version.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Define the scope of the project<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Start with one question: what does an editor need when returning to a story?<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Each reading-list entry needs five pieces of information:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Title<\/li>\n\n\n\n<li>Link (URL)<\/li>\n\n\n\n<li>Subject<\/li>\n\n\n\n<li>Saved Date<\/li>\n\n\n\n<li>Note<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Add a status field to separate unread items from those already examined.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">An editor interested in <a href=\"https:\/\/blockchainreporter.net\/bitcoin\/\">Bitcoin<\/a> could save a general topic page as a starting point and then add individual stories to the topic, including background documentation that they want to look at. The note provides the context for why each item is stored.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u201cBackground\u201d gives the editor little to work with. \u201cDid the announcement indicate a release date?\u201d identifies a task for future research sessions.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Remember these considerations as you build. A list of bookmarks is easily accumulated. A list that assists an editor to continue their work requires a bit more planning.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Start with a CSV file<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">For a single editor, CSV is an adequate starting point. The CSV file can be modified in a spreadsheet and backed up with the project.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Use column names: title, url, topic, saved_at, status and note. Before creating an importer, decide which are necessary.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Note: Although an empty note may be acceptable, an empty URL should prompt a warning message.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/github.com\/apache\/arrow\/issues\/37259\">Ruby\u2019s CSV library reads rows by header<\/a>, allowing you to refer to a field by its header. Add the csv gem to the project\u2019s Gemfile and run Bundler to install it. This makes the dependency explicit for anyone setting up the project later.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Do not split input lines based on commas. Eventually, there will be a comma in a note or quotation marks in a headline. Leave it to the CSV parser to handle these issues.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Save an intact copy of the input during development. When you encounter a row that yields an incorrect result, you will want to compare it with the actual data provided by the editor.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Limit each Ruby method to one responsibility<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">There are four tasks involved: read the file, validate the file, organize the items, and display the report.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Assign each responsibility to its own method. Names such as read_entries and render_report are perfectly suitable. If the program eventually becomes too complex to understand, you can relocate responsibilities into separate classes at that time.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A hash is all that is required to represent an item initially. After items gain their own behavior, a dedicated class for entries may become warranted.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Ruby\u2019s Enumerable methods are useful for organizing the entries. Use select with a condition to return unread entries, group_by to collect entries by topic, and sort_by to put them in the chosen order.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Decisions regarding dates require consideration of their own. The date the editor saves a link may not be the publication date of the source. Create separate fields if both dates need to be captured. Reject or flag unparseable dates rather than simply replacing them with today\u2019s date.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Duplicate Links<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Start by comparing exact URLs after trimming whitespace at either end. This catches identical addresses, though it will miss some equivalent URLs. The rule is easy to understand and test.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Eliminating query strings completely can alter where a link points. Lowercasing the entire string can also interfere with paths on server systems where case matters.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If tracking parameters cause problems, remove only a defined set that you have verified can be omitted without changing the target resource. Store the original URL in addition to the value used for comparison.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Consider the notes as well. There may be two entries pointing to the same source but noting different observations. Identify this conflict or retain both notes for evaluation. Keeping only the first note to arrive could discard valuable content.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Generate a readable HTML report<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">A static HTML page is all that is needed for the first user interface.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Display unread entries at or near the beginning of the document, along with the title, source URL, saved date and note. Display entries within topic categories so that an editor can quickly navigate back to one area without having to search through unrelated bookmarks.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Keep the destination URL visible. Identical headlines can appear on different sites, and therefore the editor should be able to determine where a link directs.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">ERB templates can define layouts. Escape imported text before inserting it into HTML. CGI.escapeHTML treats special characters appropriately when formatting text or values for quoted HTML attributes.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Validate URL destinations separately. <a href=\"https:\/\/docs.devexpress.com\/XtraReports\/405611\/common-information\/reporting-security\/safe-url-validation\">Only allow<\/a> HTTP or HTTPS URLs with hosts; escaping characters does not make an arbitrary URL safe.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Designate the HTML report as replaceable output. The CSV file contains the records. If there is an error with the layout, correct it and regenerate the report page.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Test Inputs That Will Likely Fail<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Three neat rows will tell you little about how the importer handles mistakes.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Test an empty title, a missing URL and dates in non-standard formats. Include a note with commas and quotation marks. Include two identical links with different notes. Include an article headline with angle brackets.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Test the report as well as terminal output. Angle brackets included in headlines should display correctly as text.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Messages regarding errors need to reference the failing row(s). A message such as \u201crow 12: missing URL\u201d informs users of an issue they can resolve themselves. Messages referencing errors without identifying input will confuse users.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In addition, test importing unreadable input files. The prior report should be preserved until a successful replacement report has been generated. Write the new report to a temporary file and replace the existing file once successful generation occurs.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Choose the next feature after using the tool<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Let editors use the manual version before deciding what to automate.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Repeated copying may justify a browser shortcut. Several editors changing the same CSV file would be a reason to consider a database and shared interface. A growing unread list might need an archive status before it needs a search function.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Each additional feature should address a problem encountered by users.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This Ruby programming exercise deals with concrete problems. You must parse a file, make decisions regarding imperfect input, maintain notes and generate something another person can read.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For an editor, the test is straightforward. Can they find the relevant sources when they return to a story, and see what still needs checking?<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Saving a link takes a moment. Recalling why you saved it can take considerably longer. You see a headline, so you keep the tab open. A few days later, dozens of tabs are in front of you and the detail you needed to verify is gone from memory. You have access to the source. You [&hellip;]<\/p>\n","protected":false},"author":3,"featured_media":1703,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[19],"tags":[],"class_list":["post-1701","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-ruby-projects"],"blocksy_meta":{"styles_descriptor":{"styles":{"desktop":"","tablet":"","mobile":""},"google_fonts":[],"version":7}},"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.5 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Building an Editor\u2019s Research Reading List With Ruby - Ruby-Doc Learn<\/title>\n<meta name=\"robots\" content=\"noindex, nofollow\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Building an Editor\u2019s Research Reading List With Ruby - Ruby-Doc Learn\" \/>\n<meta property=\"og:description\" content=\"Saving a link takes a moment. Recalling why you saved it can take considerably longer. You see a headline, so you keep the tab open. A few days later, dozens of tabs are in front of you and the detail you needed to verify is gone from memory. You have access to the source. You [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/ruby-doc.org\/learn\/building-an-editors-research-reading-list-with-ruby\/\" \/>\n<meta property=\"og:site_name\" content=\"Ruby-Doc Learn\" \/>\n<meta property=\"article:published_time\" content=\"2026-09-24T09:48:08+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-09-24T09:48:09+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/ruby-doc.org\/learn\/wp-content\/uploads\/2026\/09\/Building-an-Editors-Research-Reading-List-with-Ruby.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1672\" \/>\n\t<meta property=\"og:image:height\" content=\"941\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"James Britt\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"James Britt\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"6 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/ruby-doc.org\\\/learn\\\/building-an-editors-research-reading-list-with-ruby\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/ruby-doc.org\\\/learn\\\/building-an-editors-research-reading-list-with-ruby\\\/\"},\"author\":{\"@id\":\"https:\\\/\\\/ruby-doc.org\\\/learn\\\/james-britt\\\/#james-britt\"},\"headline\":\"Building an Editor\u2019s Research Reading List With Ruby\",\"datePublished\":\"2026-09-24T09:48:08+00:00\",\"dateModified\":\"2026-09-24T09:48:09+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/ruby-doc.org\\\/learn\\\/building-an-editors-research-reading-list-with-ruby\\\/\"},\"wordCount\":1167,\"publisher\":{\"@id\":\"https:\\\/\\\/ruby-doc.org\\\/learn\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/ruby-doc.org\\\/learn\\\/building-an-editors-research-reading-list-with-ruby\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/ruby-doc.org\\\/learn\\\/wp-content\\\/uploads\\\/2026\\\/09\\\/Building-an-Editors-Research-Reading-List-with-Ruby.png\",\"articleSection\":[\"Ruby Projects\"],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/ruby-doc.org\\\/learn\\\/building-an-editors-research-reading-list-with-ruby\\\/\",\"url\":\"https:\\\/\\\/ruby-doc.org\\\/learn\\\/building-an-editors-research-reading-list-with-ruby\\\/\",\"name\":\"Building an Editor\u2019s Research Reading List With Ruby - Ruby-Doc Learn\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/ruby-doc.org\\\/learn\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/ruby-doc.org\\\/learn\\\/building-an-editors-research-reading-list-with-ruby\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/ruby-doc.org\\\/learn\\\/building-an-editors-research-reading-list-with-ruby\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/ruby-doc.org\\\/learn\\\/wp-content\\\/uploads\\\/2026\\\/09\\\/Building-an-Editors-Research-Reading-List-with-Ruby.png\",\"datePublished\":\"2026-09-24T09:48:08+00:00\",\"dateModified\":\"2026-09-24T09:48:09+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/ruby-doc.org\\\/learn\\\/building-an-editors-research-reading-list-with-ruby\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/ruby-doc.org\\\/learn\\\/building-an-editors-research-reading-list-with-ruby\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/ruby-doc.org\\\/learn\\\/building-an-editors-research-reading-list-with-ruby\\\/#primaryimage\",\"url\":\"https:\\\/\\\/ruby-doc.org\\\/learn\\\/wp-content\\\/uploads\\\/2026\\\/09\\\/Building-an-Editors-Research-Reading-List-with-Ruby.png\",\"contentUrl\":\"https:\\\/\\\/ruby-doc.org\\\/learn\\\/wp-content\\\/uploads\\\/2026\\\/09\\\/Building-an-Editors-Research-Reading-List-with-Ruby.png\",\"width\":1672,\"height\":941},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/ruby-doc.org\\\/learn\\\/building-an-editors-research-reading-list-with-ruby\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/ruby-doc.org\\\/learn\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Building an Editor\u2019s Research Reading List With Ruby\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/ruby-doc.org\\\/learn\\\/#website\",\"url\":\"https:\\\/\\\/ruby-doc.org\\\/learn\\\/\",\"name\":\"Ruby-Doc Learn\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\\\/\\\/ruby-doc.org\\\/learn\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/ruby-doc.org\\\/learn\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/ruby-doc.org\\\/learn\\\/#organization\",\"name\":\"Ruby-Doc Learn\",\"url\":\"https:\\\/\\\/ruby-doc.org\\\/learn\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/ruby-doc.org\\\/learn\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/ruby-doc.org\\\/learn\\\/wp-content\\\/uploads\\\/2026\\\/09\\\/ruby-doc-logo-transparent.png\",\"contentUrl\":\"https:\\\/\\\/ruby-doc.org\\\/learn\\\/wp-content\\\/uploads\\\/2026\\\/09\\\/ruby-doc-logo-transparent.png\",\"width\":1650,\"height\":305,\"caption\":\"Ruby-Doc Learn\"},\"image\":{\"@id\":\"https:\\\/\\\/ruby-doc.org\\\/learn\\\/#\\\/schema\\\/logo\\\/image\\\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/ruby-doc.org\\\/learn\\\/james-britt\\\/#james-britt\",\"name\":\"James Britt\",\"image\":\"https:\\\/\\\/ruby-doc.org\\\/learn\\\/wp-content\\\/uploads\\\/2026\\\/09\\\/jgb_self-portrait-20140914.png\",\"description\":\"Creator and long-term maintainer of Ruby-Doc.org, founder of Neurogami, and author of practical Ruby tutorials for Ruby-Doc Learn.\",\"sameAs\":[\"https:\\\/\\\/jamesbritt.com\\\/\",\"https:\\\/\\\/neurogami.com\\\/\",\"https:\\\/\\\/www.oreilly.com\\\/pub\\\/au\\\/2595\",\"https:\\\/\\\/www.rubyevents.org\\\/profiles\\\/james-britt\"],\"url\":\"https:\\\/\\\/ruby-doc.org\\\/learn\\\/james-britt\\\/\",\"jobTitle\":\"Ruby developer and writer\",\"knowsAbout\":[\"Ruby programming language\",\"Ruby documentation\",\"JRuby\",\"Open Sound Control\",\"Software development\"],\"affiliation\":{\"@type\":\"Organization\",\"name\":\"Ruby-Doc.org\",\"url\":\"https:\\\/\\\/ruby-doc.org\\\/\"}}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Building an Editor\u2019s Research Reading List With Ruby - Ruby-Doc Learn","robots":{"index":"noindex","follow":"nofollow"},"og_locale":"en_US","og_type":"article","og_title":"Building an Editor\u2019s Research Reading List With Ruby - Ruby-Doc Learn","og_description":"Saving a link takes a moment. Recalling why you saved it can take considerably longer. You see a headline, so you keep the tab open. A few days later, dozens of tabs are in front of you and the detail you needed to verify is gone from memory. You have access to the source. You [&hellip;]","og_url":"https:\/\/ruby-doc.org\/learn\/building-an-editors-research-reading-list-with-ruby\/","og_site_name":"Ruby-Doc Learn","article_published_time":"2026-09-24T09:48:08+00:00","article_modified_time":"2026-09-24T09:48:09+00:00","og_image":[{"width":1672,"height":941,"url":"https:\/\/ruby-doc.org\/learn\/wp-content\/uploads\/2026\/09\/Building-an-Editors-Research-Reading-List-with-Ruby.png","type":"image\/png"}],"author":"James Britt","twitter_card":"summary_large_image","twitter_misc":{"Written by":"James Britt","Est. reading time":"6 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/ruby-doc.org\/learn\/building-an-editors-research-reading-list-with-ruby\/#article","isPartOf":{"@id":"https:\/\/ruby-doc.org\/learn\/building-an-editors-research-reading-list-with-ruby\/"},"author":{"@id":"https:\/\/ruby-doc.org\/learn\/james-britt\/#james-britt"},"headline":"Building an Editor\u2019s Research Reading List With Ruby","datePublished":"2026-09-24T09:48:08+00:00","dateModified":"2026-09-24T09:48:09+00:00","mainEntityOfPage":{"@id":"https:\/\/ruby-doc.org\/learn\/building-an-editors-research-reading-list-with-ruby\/"},"wordCount":1167,"publisher":{"@id":"https:\/\/ruby-doc.org\/learn\/#organization"},"image":{"@id":"https:\/\/ruby-doc.org\/learn\/building-an-editors-research-reading-list-with-ruby\/#primaryimage"},"thumbnailUrl":"https:\/\/ruby-doc.org\/learn\/wp-content\/uploads\/2026\/09\/Building-an-Editors-Research-Reading-List-with-Ruby.png","articleSection":["Ruby Projects"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/ruby-doc.org\/learn\/building-an-editors-research-reading-list-with-ruby\/","url":"https:\/\/ruby-doc.org\/learn\/building-an-editors-research-reading-list-with-ruby\/","name":"Building an Editor\u2019s Research Reading List With Ruby - Ruby-Doc Learn","isPartOf":{"@id":"https:\/\/ruby-doc.org\/learn\/#website"},"primaryImageOfPage":{"@id":"https:\/\/ruby-doc.org\/learn\/building-an-editors-research-reading-list-with-ruby\/#primaryimage"},"image":{"@id":"https:\/\/ruby-doc.org\/learn\/building-an-editors-research-reading-list-with-ruby\/#primaryimage"},"thumbnailUrl":"https:\/\/ruby-doc.org\/learn\/wp-content\/uploads\/2026\/09\/Building-an-Editors-Research-Reading-List-with-Ruby.png","datePublished":"2026-09-24T09:48:08+00:00","dateModified":"2026-09-24T09:48:09+00:00","breadcrumb":{"@id":"https:\/\/ruby-doc.org\/learn\/building-an-editors-research-reading-list-with-ruby\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/ruby-doc.org\/learn\/building-an-editors-research-reading-list-with-ruby\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/ruby-doc.org\/learn\/building-an-editors-research-reading-list-with-ruby\/#primaryimage","url":"https:\/\/ruby-doc.org\/learn\/wp-content\/uploads\/2026\/09\/Building-an-Editors-Research-Reading-List-with-Ruby.png","contentUrl":"https:\/\/ruby-doc.org\/learn\/wp-content\/uploads\/2026\/09\/Building-an-Editors-Research-Reading-List-with-Ruby.png","width":1672,"height":941},{"@type":"BreadcrumbList","@id":"https:\/\/ruby-doc.org\/learn\/building-an-editors-research-reading-list-with-ruby\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/ruby-doc.org\/learn\/"},{"@type":"ListItem","position":2,"name":"Building an Editor\u2019s Research Reading List With Ruby"}]},{"@type":"WebSite","@id":"https:\/\/ruby-doc.org\/learn\/#website","url":"https:\/\/ruby-doc.org\/learn\/","name":"Ruby-Doc Learn","description":"","publisher":{"@id":"https:\/\/ruby-doc.org\/learn\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/ruby-doc.org\/learn\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/ruby-doc.org\/learn\/#organization","name":"Ruby-Doc Learn","url":"https:\/\/ruby-doc.org\/learn\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/ruby-doc.org\/learn\/#\/schema\/logo\/image\/","url":"https:\/\/ruby-doc.org\/learn\/wp-content\/uploads\/2026\/09\/ruby-doc-logo-transparent.png","contentUrl":"https:\/\/ruby-doc.org\/learn\/wp-content\/uploads\/2026\/09\/ruby-doc-logo-transparent.png","width":1650,"height":305,"caption":"Ruby-Doc Learn"},"image":{"@id":"https:\/\/ruby-doc.org\/learn\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/ruby-doc.org\/learn\/james-britt\/#james-britt","name":"James Britt","image":"https:\/\/ruby-doc.org\/learn\/wp-content\/uploads\/2026\/09\/jgb_self-portrait-20140914.png","description":"Creator and long-term maintainer of Ruby-Doc.org, founder of Neurogami, and author of practical Ruby tutorials for Ruby-Doc Learn.","sameAs":["https:\/\/jamesbritt.com\/","https:\/\/neurogami.com\/","https:\/\/www.oreilly.com\/pub\/au\/2595","https:\/\/www.rubyevents.org\/profiles\/james-britt"],"url":"https:\/\/ruby-doc.org\/learn\/james-britt\/","jobTitle":"Ruby developer and writer","knowsAbout":["Ruby programming language","Ruby documentation","JRuby","Open Sound Control","Software development"],"affiliation":{"@type":"Organization","name":"Ruby-Doc.org","url":"https:\/\/ruby-doc.org\/"}}]}},"_links":{"self":[{"href":"https:\/\/ruby-doc.org\/learn\/wp-json\/wp\/v2\/posts\/1701","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ruby-doc.org\/learn\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/ruby-doc.org\/learn\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/ruby-doc.org\/learn\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/ruby-doc.org\/learn\/wp-json\/wp\/v2\/comments?post=1701"}],"version-history":[{"count":2,"href":"https:\/\/ruby-doc.org\/learn\/wp-json\/wp\/v2\/posts\/1701\/revisions"}],"predecessor-version":[{"id":1704,"href":"https:\/\/ruby-doc.org\/learn\/wp-json\/wp\/v2\/posts\/1701\/revisions\/1704"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/ruby-doc.org\/learn\/wp-json\/wp\/v2\/media\/1703"}],"wp:attachment":[{"href":"https:\/\/ruby-doc.org\/learn\/wp-json\/wp\/v2\/media?parent=1701"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ruby-doc.org\/learn\/wp-json\/wp\/v2\/categories?post=1701"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ruby-doc.org\/learn\/wp-json\/wp\/v2\/tags?post=1701"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}