{"id":1630,"date":"2026-09-14T11:05:40","date_gmt":"2026-09-14T10:05:40","guid":{"rendered":"https:\/\/ruby-doc.org\/learn\/?p=1630"},"modified":"2026-09-14T12:05:19","modified_gmt":"2026-09-14T11:05:19","slug":"ruby-programming-test","status":"publish","type":"post","link":"https:\/\/ruby-doc.org\/learn\/ruby-programming-test\/","title":{"rendered":"Ruby Programming Test: Newbie, Medium, Hard and Extra Hard"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Choose the version of this <strong>Ruby programming test<\/strong> that fits where you are today: <strong>Newbie, Medium, Hard or Extra Hard<\/strong>. There are ten questions at each level. Work through them in practice mode for feedback as you go, or try an exam attempt before opening the answer key. A coding challenge follows for each level.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">You can stay with one level or attempt all 40 questions together. Flag the ones you want to revisit. After submitting, use the result to pick a few concepts to practise, then retry the questions you missed or left unanswered.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1536\" height=\"1024\" src=\"https:\/\/ruby-doc.org\/learn\/wp-content\/uploads\/2026\/09\/ruby-programming-test-featured.webp\" alt=\"Ruby programming test concept with a glowing ruby, quiz cards and a laptop\" class=\"wp-image-1628\" srcset=\"https:\/\/ruby-doc.org\/learn\/wp-content\/uploads\/2026\/09\/ruby-programming-test-featured.webp 1536w, https:\/\/ruby-doc.org\/learn\/wp-content\/uploads\/2026\/09\/ruby-programming-test-featured-300x200.webp 300w, https:\/\/ruby-doc.org\/learn\/wp-content\/uploads\/2026\/09\/ruby-programming-test-featured-1024x683.webp 1024w, https:\/\/ruby-doc.org\/learn\/wp-content\/uploads\/2026\/09\/ruby-programming-test-featured-768x512.webp 768w\" sizes=\"auto, (max-width: 1536px) 100vw, 1536px\" \/><figcaption class=\"wp-element-caption\">Practise Ruby concepts, check your reasoning and work through code challenges.<\/figcaption><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">How to use this Ruby programming test<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Set aside around 8\u201315 minutes for ten questions, with more time for the longer Hard and Extra Hard snippets. None of the levels has a countdown. If you have only just started Ruby, choose Newbie and take your time reading each line. You do not need Rails knowledge.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Make a prediction before running any code. Then choose an answer. In practice mode, Check answer reveals the explanation and locks that choice for this attempt. Exam mode lets you revise your choices until you submit. Flagging a question simply marks it for your attention; it does not change its score.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Scoring is straightforward: one point for a correct answer and zero for an incorrect or unanswered one. A level is scored out of ten, while the mixed test is out of 40. The coding challenges have their own checks and stay outside that percentage. The browser saves your current quiz attempt when local storage is available; Reset this attempt clears it.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Choose your Ruby programming test level<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Newbie:<\/strong> ten questions on truthiness, arithmetic, interpolation, ranges, basic array operations, simple Hash lookups, return values and nil. Start here if you have read a few Ruby snippets but still find yourself guessing their output.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Medium:<\/strong> ten questions on shared references, transformations, fetch defaults, keyword arguments, blocks, instance state, iteration, ensure and input conversion. This level suits someone who can write a short method and wants to catch everyday mistakes.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Hard:<\/strong> ten questions on shared Hash defaults, shallow freezing, String keys, Proc and lambda argument handling, prepend, rescue scope, false-valued memoisation and accumulators. Trace the objects and method calls carefully; familiar-looking code can behave differently from your first guess.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Extra Hard:<\/strong> ten questions on closure capture, nonlocal returns, lazy enumeration, regular-expression anchors, keyword separation, constant lookup, refinements, module order, pattern matching and identity-based Hashes. This is intended for readers already comfortable with Ruby methods and collections.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">These levels describe the difficulty of this question bank. They are not certifications or standard job grades. The quiz does not assess Rails, database design, concurrency, application security or your ability to maintain a production system.<\/p>\n\n\n\n<div class=\"wp-block-group rpt-test is-layout-constrained wp-block-group-is-layout-constrained\">\n<h2 class=\"wp-block-heading\">Start the interactive Ruby programming test<\/h2>\n\n\n\n<div class=\"wp-block-group rpt-app is-layout-constrained wp-block-group-is-layout-constrained\">\n<p class=\"wp-block-paragraph\">Choose an answer for each question, then open its explanation to check your reasoning. Each correct answer is worth one point. Choose a level and work through its ten questions.<\/p>\n<\/div>\n\n\n\n<div class=\"wp-block-group rpt-bank is-layout-constrained wp-block-group-is-layout-constrained\">\n<h3 class=\"wp-block-heading\">Ruby programming test questions<\/h3>\n\n\n\n<h3 class=\"wp-block-heading\">Newbie Ruby programming test<\/h3>\n\n\n\n<div class=\"wp-block-group rpt-question rpt-topic-basics rpt-level-newbie rpt-answer-1 is-layout-constrained wp-block-group-is-layout-constrained\">\n<p class=\"rpt-topic wp-block-paragraph\">Basics<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Does zero count as true?<\/h4>\n\n\n\n<p class=\"rpt-prompt wp-block-paragraph\">What does this program print?<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>puts(0 ? \"runs\" : \"skips\")<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list rpt-options\">\n<li>A. skips<\/li>\n\n\n\n<li>B. runs<\/li>\n\n\n\n<li>C. 0<\/li>\n\n\n\n<li>D. It raises TypeError<\/li>\n<\/ul>\n\n\n\n<details class=\"wp-block-details rpt-explanation is-layout-flow wp-block-details-is-layout-flow\"><summary>Show answer and explanation<\/summary>\n<p class=\"wp-block-paragraph\"><strong>Answer B.<\/strong> Zero takes the first branch in Ruby. The two falsey values are false and nil; everything else is truthy, including an empty String or Array. If you expected skips, check whether you brought a truth rule over from another language.<\/p>\n<\/details>\n<\/div>\n\n\n\n<div class=\"wp-block-group rpt-question rpt-topic-basics rpt-level-newbie rpt-answer-2 is-layout-constrained wp-block-group-is-layout-constrained\">\n<p class=\"rpt-topic wp-block-paragraph\">Basics<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Integer and floating-point division<\/h4>\n\n\n\n<p class=\"rpt-prompt wp-block-paragraph\">What does p display?<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>p &#91;7 \/ 2, 7 \/ 2.0]<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list rpt-options\">\n<li>A. [3.5, 3.5]<\/li>\n\n\n\n<li>B. [3, 3]<\/li>\n\n\n\n<li>C. [3, 3.5]<\/li>\n\n\n\n<li>D. [4, 3.5]<\/li>\n<\/ul>\n\n\n\n<details class=\"wp-block-details rpt-explanation is-layout-flow wp-block-details-is-layout-flow\"><summary>Show answer and explanation<\/summary>\n<p class=\"wp-block-paragraph\"><strong>Answer C.<\/strong> With two Integer operands, 7 \/ 2 gives 3. Change either operand to a Float and the result can contain a fractional part: 7 \/ 2.0 gives 3.5. The types going into the calculation matter.<\/p>\n<\/details>\n<\/div>\n\n\n\n<div class=\"wp-block-group rpt-question rpt-topic-basics rpt-level-newbie rpt-answer-0 is-layout-constrained wp-block-group-is-layout-constrained\">\n<p class=\"rpt-topic wp-block-paragraph\">Basics<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">String interpolation<\/h4>\n\n\n\n<p class=\"rpt-prompt wp-block-paragraph\">Which two lines are printed, in order?<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>name = \"Ada\"\nputs \"Hello #{name}\"\nputs 'Hello #{name}'<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list rpt-options\">\n<li>A. Hello Ada then Hello #{name}<\/li>\n\n\n\n<li>B. Hello Ada then Hello Ada<\/li>\n\n\n\n<li>C. Hello #{name} then Hello #{name}<\/li>\n\n\n\n<li>D. It raises NameError<\/li>\n<\/ul>\n\n\n\n<details class=\"wp-block-details rpt-explanation is-layout-flow wp-block-details-is-layout-flow\"><summary>Show answer and explanation<\/summary>\n<p class=\"wp-block-paragraph\"><strong>Answer A.<\/strong> The double-quoted greeting inserts Ada. The single-quoted greeting keeps #{name} as literal characters. If a message prints the placeholder you meant to replace, its quote style is a useful first thing to check.<\/p>\n<\/details>\n<\/div>\n\n\n\n<div class=\"wp-block-group rpt-question rpt-topic-basics rpt-level-newbie rpt-answer-3 is-layout-constrained wp-block-group-is-layout-constrained\">\n<p class=\"rpt-topic wp-block-paragraph\">Basics<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">An exclusive range<\/h4>\n\n\n\n<p class=\"rpt-prompt wp-block-paragraph\">What is the resulting array?<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>p (1...4).to_a<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list rpt-options\">\n<li>A. [1, 2, 3, 4]<\/li>\n\n\n\n<li>B. [2, 3, 4]<\/li>\n\n\n\n<li>C. [1, 4]<\/li>\n\n\n\n<li>D. [1, 2, 3]<\/li>\n<\/ul>\n\n\n\n<details class=\"wp-block-details rpt-explanation is-layout-flow wp-block-details-is-layout-flow\"><summary>Show answer and explanation<\/summary>\n<p class=\"wp-block-paragraph\"><strong>Answer D.<\/strong> The extra dot leaves 4 out, giving [1, 2, 3]. Writing 1..4 would include it. In both cases the range starts at 1; only the treatment of the end value changes.<\/p>\n<\/details>\n<\/div>\n\n\n\n<div class=\"wp-block-group rpt-question rpt-topic-collections rpt-level-newbie rpt-answer-0 is-layout-constrained wp-block-group-is-layout-constrained\">\n<p class=\"rpt-topic wp-block-paragraph\">Collections<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Selecting matching values<\/h4>\n\n\n\n<p class=\"rpt-prompt wp-block-paragraph\">Which array is printed?<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>p &#91;1, 2, 3, 4].select { |n| n.odd? }<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list rpt-options\">\n<li>A. [1, 3]<\/li>\n\n\n\n<li>B. [true, false, true, false]<\/li>\n\n\n\n<li>C. [2, 4]<\/li>\n\n\n\n<li>D. [1, 2, 3, 4]<\/li>\n<\/ul>\n\n\n\n<details class=\"wp-block-details rpt-explanation is-layout-flow wp-block-details-is-layout-flow\"><summary>Show answer and explanation<\/summary>\n<p class=\"wp-block-paragraph\"><strong>Answer A.<\/strong> The odd numbers survive, so you get [1, 3]. select keeps an original element whenever its block result is truthy. To collect the true and false results themselves, you would use map.<\/p>\n<\/details>\n<\/div>\n\n\n\n<div class=\"wp-block-group rpt-question rpt-topic-collections rpt-level-newbie rpt-answer-3 is-layout-constrained wp-block-group-is-layout-constrained\">\n<p class=\"rpt-topic wp-block-paragraph\">Collections<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">What compact actually removes<\/h4>\n\n\n\n<p class=\"rpt-prompt wp-block-paragraph\">Which elements survive?<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>p &#91;nil, false, 0, \"\"].compact<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list rpt-options\">\n<li>A. []<\/li>\n\n\n\n<li>B. [0]<\/li>\n\n\n\n<li>C. [false]<\/li>\n\n\n\n<li>D. [false, 0, &#8220;&#8221;]<\/li>\n<\/ul>\n\n\n\n<details class=\"wp-block-details rpt-explanation is-layout-flow wp-block-details-is-layout-flow\"><summary>Show answer and explanation<\/summary>\n<p class=\"wp-block-paragraph\"><strong>Answer D.<\/strong> Only nil disappears. false, 0 and the empty string all remain in the returned array. Cleaning blank text as well would need another condition; compact has a narrower job.<\/p>\n<\/details>\n<\/div>\n\n\n\n<div class=\"wp-block-group rpt-question rpt-topic-collections rpt-level-newbie rpt-answer-1 is-layout-constrained wp-block-group-is-layout-constrained\">\n<p class=\"rpt-topic wp-block-paragraph\">Collections<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Symbol keys and string keys<\/h4>\n\n\n\n<p class=\"rpt-prompt wp-block-paragraph\">What does this lookup return?<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>settings = { timeout: 5 }\np settings&#91;\"timeout\"]<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list rpt-options\">\n<li>A. 5<\/li>\n\n\n\n<li>B. nil<\/li>\n\n\n\n<li>C. false<\/li>\n\n\n\n<li>D. It raises KeyError<\/li>\n<\/ul>\n\n\n\n<details class=\"wp-block-details rpt-explanation is-layout-flow wp-block-details-is-layout-flow\"><summary>Show answer and explanation<\/summary>\n<p class=\"wp-block-paragraph\"><strong>Answer B.<\/strong> timeout: creates a Symbol key, :timeout. Looking for the String key &#8220;timeout&#8221; misses it and returns nil. Rails users should take particular care here: an ordinary core Ruby Hash has no automatic indifferent access.<\/p>\n<\/details>\n<\/div>\n\n\n\n<div class=\"wp-block-group rpt-question rpt-topic-methods rpt-level-newbie rpt-answer-1 is-layout-constrained wp-block-group-is-layout-constrained\">\n<p class=\"rpt-topic wp-block-paragraph\">Methods<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">A method&#8217;s return value<\/h4>\n\n\n\n<p class=\"rpt-prompt wp-block-paragraph\">What does p print?<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>def double(number)\n  number * 2\n  \"done\"\nend\np double(4)<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list rpt-options\">\n<li>A. 8<\/li>\n\n\n\n<li>B. &#8220;done&#8221;<\/li>\n\n\n\n<li>C. nil<\/li>\n\n\n\n<li>D. [8, &#8220;done&#8221;]<\/li>\n<\/ul>\n\n\n\n<details class=\"wp-block-details rpt-explanation is-layout-flow wp-block-details-is-layout-flow\"><summary>Show answer and explanation<\/summary>\n<p class=\"wp-block-paragraph\"><strong>Answer B.<\/strong> The multiplication produces 8, but the method goes on to evaluate &#8220;done&#8221;. That last expression becomes its return value. Move the multiplication to the end, or return it explicitly, if 8 is what the caller needs.<\/p>\n<\/details>\n<\/div>\n\n\n\n<div class=\"wp-block-group rpt-question rpt-topic-debugging rpt-level-newbie rpt-answer-2 is-layout-constrained wp-block-group-is-layout-constrained\">\n<p class=\"rpt-topic wp-block-paragraph\">Debugging<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Safe navigation stops at nil<\/h4>\n\n\n\n<p class=\"rpt-prompt wp-block-paragraph\">What does this expression return?<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>user = nil\np user&amp;.upcase<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list rpt-options\">\n<li>A. false<\/li>\n\n\n\n<li>B. &#8220;&#8221;<\/li>\n\n\n\n<li>C. nil<\/li>\n\n\n\n<li>D. It raises NoMethodError<\/li>\n<\/ul>\n\n\n\n<details class=\"wp-block-details rpt-explanation is-layout-flow wp-block-details-is-layout-flow\"><summary>Show answer and explanation<\/summary>\n<p class=\"wp-block-paragraph\"><strong>Answer C.<\/strong> The receiver is nil, so &amp;. skips upcase and returns nil. It only provides that shortcut for nil. A false receiver would still receive the method call, and exceptions from a method that actually runs can still escape.<\/p>\n<\/details>\n<\/div>\n\n\n\n<div class=\"wp-block-group rpt-question rpt-topic-debugging rpt-level-newbie rpt-answer-3 is-layout-constrained wp-block-group-is-layout-constrained\">\n<p class=\"rpt-topic wp-block-paragraph\">Debugging<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">An out-of-range array index<\/h4>\n\n\n\n<p class=\"rpt-prompt wp-block-paragraph\">What does the ordinary bracket lookup return?<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>colors = &#91;:red, :blue]\np colors&#91;5]<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list rpt-options\">\n<li>A. It raises IndexError<\/li>\n\n\n\n<li>B. It returns :blue<\/li>\n\n\n\n<li>C. It wraps around to :red<\/li>\n\n\n\n<li>D. nil<\/li>\n<\/ul>\n\n\n\n<details class=\"wp-block-details rpt-explanation is-layout-flow wp-block-details-is-layout-flow\"><summary>Show answer and explanation<\/summary>\n<p class=\"wp-block-paragraph\"><strong>Answer D.<\/strong> Index 5 is outside this two-element array, and the bracket lookup returns nil. If a missing position should fail loudly, Array#fetch can raise IndexError instead; it also supports an explicit default.<\/p>\n<\/details>\n<\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Medium Ruby programming test<\/h3>\n\n\n\n<div class=\"wp-block-group rpt-question rpt-topic-basics rpt-level-medium rpt-answer-1 is-layout-constrained wp-block-group-is-layout-constrained\">\n<p class=\"rpt-topic wp-block-paragraph\">Basics<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Two references, one string<\/h4>\n\n\n\n<p class=\"rpt-prompt wp-block-paragraph\">Assume the default mutable string behavior shown here. What prints?<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># frozen_string_literal: false\na = \"ruby\"\nb = a\nb.upcase!\nputs a<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list rpt-options\">\n<li>A. ruby<\/li>\n\n\n\n<li>B. RUBY<\/li>\n\n\n\n<li>C. nil<\/li>\n\n\n\n<li>D. It always raises FrozenError<\/li>\n<\/ul>\n\n\n\n<details class=\"wp-block-details rpt-explanation is-layout-flow wp-block-details-is-layout-flow\"><summary>Show answer and explanation<\/summary>\n<p class=\"wp-block-paragraph\"><strong>Answer B.<\/strong> One mutable String is being referenced by two variables. Modifying it through b means that a also sees RUBY. The first line explicitly selects mutable string literals, so this snippet does not raise FrozenError.<\/p>\n<\/details>\n<\/div>\n\n\n\n<div class=\"wp-block-group rpt-question rpt-topic-collections rpt-level-medium rpt-answer-2 is-layout-constrained wp-block-group-is-layout-constrained\">\n<p class=\"rpt-topic wp-block-paragraph\">Collections<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Mapping without replacing the original array<\/h4>\n\n\n\n<p class=\"rpt-prompt wp-block-paragraph\">What are the two output lines?<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>numbers = &#91;1, 2, 3]\ndoubled = numbers.map { |n| n * 2 }\np numbers\np doubled<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list rpt-options\">\n<li>A. [2, 4, 6] then [2, 4, 6]<\/li>\n\n\n\n<li>B. [1, 2, 3] then nil<\/li>\n\n\n\n<li>C. [1, 2, 3] then [2, 4, 6]<\/li>\n\n\n\n<li>D. nil then [2, 4, 6]<\/li>\n<\/ul>\n\n\n\n<details class=\"wp-block-details rpt-explanation is-layout-flow wp-block-details-is-layout-flow\"><summary>Show answer and explanation<\/summary>\n<p class=\"wp-block-paragraph\"><strong>Answer C.<\/strong> numbers remains [1, 2, 3], and doubled becomes [2, 4, 6]. map creates a new array from the values produced by its block. But a mutable object used inside that block, such as a String, could still be changed even while a new result array is being built.<\/p>\n<\/details>\n<\/div>\n\n\n\n<div class=\"wp-block-group rpt-question rpt-topic-collections rpt-level-medium rpt-answer-2 is-layout-constrained wp-block-group-is-layout-constrained\">\n<p class=\"rpt-topic wp-block-paragraph\">Collections<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">A missing key versus a nil value<\/h4>\n\n\n\n<p class=\"rpt-prompt wp-block-paragraph\">What does fetch return in these two cases?<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>limits = { max: nil }\np &#91;limits.fetch(:max, 10), limits.fetch(:missing, 10)]<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list rpt-options\">\n<li>A. [10, 10]<\/li>\n\n\n\n<li>B. [nil, nil]<\/li>\n\n\n\n<li>C. [nil, 10]<\/li>\n\n\n\n<li>D. It raises KeyError<\/li>\n<\/ul>\n\n\n\n<details class=\"wp-block-details rpt-explanation is-layout-flow wp-block-details-is-layout-flow\"><summary>Show answer and explanation<\/summary>\n<p class=\"wp-block-paragraph\"><strong>Answer C.<\/strong> There are two scenarios. :max exists and its value is nil, so fetch returns that value. :missing does not exist at all; here fetch uses its second argument, 10. This distinction helps when an explicit nil means something in your data.<\/p>\n<\/details>\n<\/div>\n\n\n\n<div class=\"wp-block-group rpt-question rpt-topic-methods rpt-level-medium rpt-answer-3 is-layout-constrained wp-block-group-is-layout-constrained\">\n<p class=\"rpt-topic wp-block-paragraph\">Methods<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Passing a keyword argument<\/h4>\n\n\n\n<p class=\"rpt-prompt wp-block-paragraph\">Which greeting is printed?<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>def label(name, prefix: \"Hi\")\n  \"#{prefix}, #{name}\"\nend\nputs label(\"Ada\", prefix: \"Hello\")<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list rpt-options\">\n<li>A. Hi, Ada<\/li>\n\n\n\n<li>B. Ada, Hello<\/li>\n\n\n\n<li>C. It raises ArgumentError<\/li>\n\n\n\n<li>D. Hello, Ada<\/li>\n<\/ul>\n\n\n\n<details class=\"wp-block-details rpt-explanation is-layout-flow wp-block-details-is-layout-flow\"><summary>Show answer and explanation<\/summary>\n<p class=\"wp-block-paragraph\"><strong>Answer D.<\/strong> Hello replaces the default Hi for this particular call, giving Hello, Ada. prefix: is the keyword argument, while Ada fills the positional name parameter. Follow the definition and the call together to see which argument supplies each value.<\/p>\n<\/details>\n<\/div>\n\n\n\n<div class=\"wp-block-group rpt-question rpt-topic-methods rpt-level-medium rpt-answer-0 is-layout-constrained wp-block-group-is-layout-constrained\">\n<p class=\"rpt-topic wp-block-paragraph\">Methods<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Passing a value to a block<\/h4>\n\n\n\n<p class=\"rpt-prompt wp-block-paragraph\">What is the method&#8217;s result?<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>def with_value\n  yield 2\nend\np with_value { |n| n * 3 }<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list rpt-options\">\n<li>A. 6<\/li>\n\n\n\n<li>B. 2<\/li>\n\n\n\n<li>C. 3<\/li>\n\n\n\n<li>D. nil<\/li>\n<\/ul>\n\n\n\n<details class=\"wp-block-details rpt-explanation is-layout-flow wp-block-details-is-layout-flow\"><summary>Show answer and explanation<\/summary>\n<p class=\"wp-block-paragraph\"><strong>Answer A.<\/strong> Look at the value flowing through the call: yield passes 2 into the block, the block multiplies it by 3, and the method returns that product. The number printed is 6.<\/p>\n<\/details>\n<\/div>\n\n\n\n<div class=\"wp-block-group rpt-question rpt-topic-methods rpt-level-medium rpt-answer-2 is-layout-constrained wp-block-group-is-layout-constrained\">\n<p class=\"rpt-topic wp-block-paragraph\">Methods<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Separate instance state<\/h4>\n\n\n\n<p class=\"rpt-prompt wp-block-paragraph\">What values do the two objects hold?<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>class Counter\n  attr_reader :value\n  def initialize\n    @value = 0\n  end\n  def increment\n    @value += 1\n  end\nend\na = Counter.new\nb = Counter.new\na.increment\np &#91;a.value, b.value]<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list rpt-options\">\n<li>A. [1, 1]<\/li>\n\n\n\n<li>B. [0, 0]<\/li>\n\n\n\n<li>C. [1, 0]<\/li>\n\n\n\n<li>D. It raises NoMethodError<\/li>\n<\/ul>\n\n\n\n<details class=\"wp-block-details rpt-explanation is-layout-flow wp-block-details-is-layout-flow\"><summary>Show answer and explanation<\/summary>\n<p class=\"wp-block-paragraph\"><strong>Answer C.<\/strong> a has been incremented once; b has not. Their @value variables are therefore 1 and 0 respectively. The reader created by attr_reader lets us retrieve those values without making them shared class state.<\/p>\n<\/details>\n<\/div>\n\n\n\n<div class=\"wp-block-group rpt-question rpt-topic-methods rpt-level-medium rpt-answer-1 is-layout-constrained wp-block-group-is-layout-constrained\">\n<p class=\"rpt-topic wp-block-paragraph\">Methods<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">each is not map<\/h4>\n\n\n\n<p class=\"rpt-prompt wp-block-paragraph\">Which value is assigned to result?<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>result = &#91;1, 2].each { |n| n * 10 }\np result<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list rpt-options\">\n<li>A. [10, 20]<\/li>\n\n\n\n<li>B. [1, 2]<\/li>\n\n\n\n<li>C. 20<\/li>\n\n\n\n<li>D. nil<\/li>\n<\/ul>\n\n\n\n<details class=\"wp-block-details rpt-explanation is-layout-flow wp-block-details-is-layout-flow\"><summary>Show answer and explanation<\/summary>\n<p class=\"wp-block-paragraph\"><strong>Answer B.<\/strong> The products are generated and then discarded. When this Array#each call completes normally, it returns [1, 2], the array it traversed. Use map when you want a new array containing the products.<\/p>\n<\/details>\n<\/div>\n\n\n\n<div class=\"wp-block-group rpt-question rpt-topic-debugging rpt-level-medium rpt-answer-3 is-layout-constrained wp-block-group-is-layout-constrained\">\n<p class=\"rpt-topic wp-block-paragraph\">Debugging<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Requiring a Hash key<\/h4>\n\n\n\n<p class=\"rpt-prompt wp-block-paragraph\">Which message is printed?<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>settings = {}\nbegin\n  settings.fetch(:token)\nrescue KeyError\n  puts \"missing token\"\nend<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list rpt-options\">\n<li>A. nil<\/li>\n\n\n\n<li>B. false<\/li>\n\n\n\n<li>C. Nothing is printed<\/li>\n\n\n\n<li>D. missing token<\/li>\n<\/ul>\n\n\n\n<details class=\"wp-block-details rpt-explanation is-layout-flow wp-block-details-is-layout-flow\"><summary>Show answer and explanation<\/summary>\n<p class=\"wp-block-paragraph\"><strong>Answer D.<\/strong> The required :token key is missing. fetch raises KeyError, so the rescue prints missing token. Bracket access would return nil in its place. Whether that absence counts as an error is a decision for your application.<\/p>\n<\/details>\n<\/div>\n\n\n\n<div class=\"wp-block-group rpt-question rpt-topic-debugging rpt-level-medium rpt-answer-0 is-layout-constrained wp-block-group-is-layout-constrained\">\n<p class=\"rpt-topic wp-block-paragraph\">Debugging<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">ensure and the return value<\/h4>\n\n\n\n<p class=\"rpt-prompt wp-block-paragraph\">Which two lines appear, in order?<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>def answer\n  7\nensure\n  puts \"cleanup\"\nend\np answer<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list rpt-options\">\n<li>A. cleanup then 7<\/li>\n\n\n\n<li>B. 7 then cleanup<\/li>\n\n\n\n<li>C. cleanup then nil<\/li>\n\n\n\n<li>D. Only cleanup<\/li>\n<\/ul>\n\n\n\n<details class=\"wp-block-details rpt-explanation is-layout-flow wp-block-details-is-layout-flow\"><summary>Show answer and explanation<\/summary>\n<p class=\"wp-block-paragraph\"><strong>Answer A.<\/strong> cleanup prints before the caller receives 7. ensure executes as the method ends, but its ordinary puts statement leaves the pending return value intact. An explicit return in ensure would change that behavior.<\/p>\n<\/details>\n<\/div>\n\n\n\n<div class=\"wp-block-group rpt-question rpt-topic-debugging rpt-level-medium rpt-answer-1 is-layout-constrained wp-block-group-is-layout-constrained\">\n<p class=\"rpt-topic wp-block-paragraph\">Debugging<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">A conversion with trailing text<\/h4>\n\n\n\n<p class=\"rpt-prompt wp-block-paragraph\">Which pair is printed?<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>lenient = \"12cats\".to_i\nbegin\n  strict = Integer(\"12cats\", 10)\nrescue ArgumentError\n  strict = :invalid\nend\np &#91;lenient, strict]<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list rpt-options\">\n<li>A. [0, :invalid]<\/li>\n\n\n\n<li>B. [12, :invalid]<\/li>\n\n\n\n<li>C. [12, 12]<\/li>\n\n\n\n<li>D. [nil, nil]<\/li>\n<\/ul>\n\n\n\n<details class=\"wp-block-details rpt-explanation is-layout-flow wp-block-details-is-layout-flow\"><summary>Show answer and explanation<\/summary>\n<p class=\"wp-block-paragraph\"><strong>Answer B.<\/strong> to_i accepts the leading 12 and ignores the trailing cats. Integer with base 10 rejects those letters, so the rescue supplies :invalid. Before choosing a conversion for user-entered text, decide which behavior its input contract needs.<\/p>\n<\/details>\n<\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Hard Ruby programming test<\/h3>\n\n\n\n<div class=\"wp-block-group rpt-question rpt-topic-collections rpt-level-hard rpt-answer-2 is-layout-constrained wp-block-group-is-layout-constrained\">\n<p class=\"rpt-topic wp-block-paragraph\">Collections<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">A shared Hash default<\/h4>\n\n\n\n<p class=\"rpt-prompt wp-block-paragraph\">What does this Hash contain after the append?<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>groups = Hash.new(&#91;])\ngroups&#91;:a] &lt;&lt; 1\np &#91;groups&#91;:b], groups.keys]<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list rpt-options\">\n<li>A. [[1], [:a]]<\/li>\n\n\n\n<li>B. [[], [:a]]<\/li>\n\n\n\n<li>C. [[1], []]<\/li>\n\n\n\n<li>D. [nil, []]<\/li>\n<\/ul>\n\n\n\n<details class=\"wp-block-details rpt-explanation is-layout-flow wp-block-details-is-layout-flow\"><summary>Show answer and explanation<\/summary>\n<p class=\"wp-block-paragraph\"><strong>Answer C.<\/strong> No entries have been added to the Hash. Missing keys return the same default array, which now contains 1. One useful fix for separate per-key containers is a default block that assigns a fresh array to the missing key.<\/p>\n<\/details>\n<\/div>\n\n\n\n<div class=\"wp-block-group rpt-question rpt-topic-collections rpt-level-hard rpt-answer-1 is-layout-constrained wp-block-group-is-layout-constrained\">\n<p class=\"rpt-topic wp-block-paragraph\">Collections<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Freezing a container<\/h4>\n\n\n\n<p class=\"rpt-prompt wp-block-paragraph\">What happens when the nested string is changed?<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># frozen_string_literal: false\nitems = &#91;\"a\"]\nitems.freeze\nitems.first &lt;&lt; \"b\"\np items<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list rpt-options\">\n<li>A. It raises FrozenError<\/li>\n\n\n\n<li>B. [&#8220;ab&#8221;]<\/li>\n\n\n\n<li>C. [&#8220;a&#8221;]<\/li>\n\n\n\n<li>D. [&#8220;a&#8221;, &#8220;b&#8221;]<\/li>\n<\/ul>\n\n\n\n<details class=\"wp-block-details rpt-explanation is-layout-flow wp-block-details-is-layout-flow\"><summary>Show answer and explanation<\/summary>\n<p class=\"wp-block-paragraph\"><strong>Answer B.<\/strong> Although the array is frozen, the String inside it remains mutable. Appending b changes the String to ab without replacing an element or adding a new element to the array. Freezing that outer container does not recursively freeze its contents.<\/p>\n<\/details>\n<\/div>\n\n\n\n<div class=\"wp-block-group rpt-question rpt-topic-collections rpt-level-hard rpt-answer-3 is-layout-constrained wp-block-group-is-layout-constrained\">\n<p class=\"rpt-topic wp-block-paragraph\">Collections<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">A String used as an ordinary Hash key<\/h4>\n\n\n\n<p class=\"rpt-prompt wp-block-paragraph\">Which lookups succeed after the original string changes?<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># frozen_string_literal: false\nkey = \"a\"\nlookup = { key =&gt; 1 }\nkey.upcase!\np &#91;lookup&#91;\"a\"], lookup&#91;\"A\"]]<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list rpt-options\">\n<li>A. [nil, 1]<\/li>\n\n\n\n<li>B. [1, 1]<\/li>\n\n\n\n<li>C. [nil, nil]<\/li>\n\n\n\n<li>D. [1, nil]<\/li>\n<\/ul>\n\n\n\n<details class=\"wp-block-details rpt-explanation is-layout-flow wp-block-details-is-layout-flow\"><summary>Show answer and explanation<\/summary>\n<p class=\"wp-block-paragraph\"><strong>Answer D.<\/strong> The stored key remains a. An ordinary Hash duplicates and freezes an unfrozen String key, so modifying the original String later has no effect on that stored copy. String keys receive special treatment; other mutable key objects are not guaranteed the same behavior.<\/p>\n<\/details>\n<\/div>\n\n\n\n<div class=\"wp-block-group rpt-question rpt-topic-methods rpt-level-hard rpt-answer-0 is-layout-constrained wp-block-group-is-layout-constrained\">\n<p class=\"rpt-topic wp-block-paragraph\">Methods<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Lambda argument counts<\/h4>\n\n\n\n<p class=\"rpt-prompt wp-block-paragraph\">Which branch runs?<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>add = -&gt;(a, b) { a + b }\nbegin\n  add.call(1)\nrescue ArgumentError\n  puts \"wrong argument count\"\nend<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list rpt-options\">\n<li>A. wrong argument count<\/li>\n\n\n\n<li>B. The result is 1<\/li>\n\n\n\n<li>C. The result is nil<\/li>\n\n\n\n<li>D. It raises TypeError instead<\/li>\n<\/ul>\n\n\n\n<details class=\"wp-block-details rpt-explanation is-layout-flow wp-block-details-is-layout-flow\"><summary>Show answer and explanation<\/summary>\n<p class=\"wp-block-paragraph\"><strong>Answer A.<\/strong> The lambda expects two arguments and receives only one. ArgumentError is raised before a + b can be evaluated, and the rescue prints wrong argument count. Compare its argument handling with the ordinary Proc in the following question.<\/p>\n<\/details>\n<\/div>\n\n\n\n<div class=\"wp-block-group rpt-question rpt-topic-methods rpt-level-hard rpt-answer-1 is-layout-constrained wp-block-group-is-layout-constrained\">\n<p class=\"rpt-topic wp-block-paragraph\">Methods<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">A non-lambda Proc&#8217;s missing argument<\/h4>\n\n\n\n<p class=\"rpt-prompt wp-block-paragraph\">What does this simple Proc receive?<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>pair = proc { |a, b| &#91;a, b] }\np pair.call(1)<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list rpt-options\">\n<li>A. It raises ArgumentError<\/li>\n\n\n\n<li>B. [1, nil]<\/li>\n\n\n\n<li>C. [1, 1]<\/li>\n\n\n\n<li>D. [nil, nil]<\/li>\n<\/ul>\n\n\n\n<details class=\"wp-block-details rpt-explanation is-layout-flow wp-block-details-is-layout-flow\"><summary>Show answer and explanation<\/summary>\n<p class=\"wp-block-paragraph\"><strong>Answer B.<\/strong> The missing second positional argument becomes nil, producing [1, nil]. This lenient behavior belongs to the non-lambda Proc with ordinary block parameters shown here. Keep keyword arguments and more complex destructuring arrangements separate when reasoning about argument rules.<\/p>\n<\/details>\n<\/div>\n\n\n\n<div class=\"wp-block-group rpt-question rpt-topic-methods rpt-level-hard rpt-answer-2 is-layout-constrained wp-block-group-is-layout-constrained\">\n<p class=\"rpt-topic wp-block-paragraph\">Methods<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">prepend and super<\/h4>\n\n\n\n<p class=\"rpt-prompt wp-block-paragraph\">Which name is printed?<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>module Tagged\n  def name\n    \"tag:\" + super\n  end\nend\nclass Report\n  prepend Tagged\n  def name\n    \"report\"\n  end\nend\nputs Report.new.name<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list rpt-options\">\n<li>A. report<\/li>\n\n\n\n<li>B. tag:<\/li>\n\n\n\n<li>C. tag:report<\/li>\n\n\n\n<li>D. It recurses forever<\/li>\n<\/ul>\n\n\n\n<details class=\"wp-block-details rpt-explanation is-layout-flow wp-block-details-is-layout-flow\"><summary>Show answer and explanation<\/summary>\n<p class=\"wp-block-paragraph\"><strong>Answer C.<\/strong> Tagged runs before Report because it was prepended. Its super reaches Report#name, which supplies report. Tagged#name then adds the prefix, leaving tag:report as the returned name.<\/p>\n<\/details>\n<\/div>\n\n\n\n<div class=\"wp-block-group rpt-question rpt-topic-debugging rpt-level-hard rpt-answer-3 is-layout-constrained wp-block-group-is-layout-constrained\">\n<p class=\"rpt-topic wp-block-paragraph\">Debugging<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Choosing the rescue scope<\/h4>\n\n\n\n<p class=\"rpt-prompt wp-block-paragraph\">Which rescue prints a message?<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>begin\n  begin\n    raise NotImplementedError\n  rescue StandardError\n    puts \"inner\"\n  end\nrescue NotImplementedError\n  puts \"outer\"\nend<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list rpt-options\">\n<li>A. inner<\/li>\n\n\n\n<li>B. Both inner and outer<\/li>\n\n\n\n<li>C. Neither; the program exits unhandled<\/li>\n\n\n\n<li>D. outer<\/li>\n<\/ul>\n\n\n\n<details class=\"wp-block-details rpt-explanation is-layout-flow wp-block-details-is-layout-flow\"><summary>Show answer and explanation<\/summary>\n<p class=\"wp-block-paragraph\"><strong>Answer D.<\/strong> The outer rescue catches the exception. NotImplementedError lies outside the StandardError branch and therefore passes the inner rescue. A bare rescue defaults to StandardError too; it would not catch every Exception type.<\/p>\n<\/details>\n<\/div>\n\n\n\n<div class=\"wp-block-group rpt-question rpt-topic-debugging rpt-level-hard rpt-answer-1 is-layout-constrained wp-block-group-is-layout-constrained\">\n<p class=\"rpt-topic wp-block-paragraph\">Debugging<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Memoising a false result<\/h4>\n\n\n\n<p class=\"rpt-prompt wp-block-paragraph\">How many times is the calculation performed?<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>class Probe\n  attr_reader :calls\n  def initialize\n    @calls = 0\n  end\n  def ready?\n    @ready ||= begin\n      @calls += 1\n      false\n    end\n  end\nend\nprobe = Probe.new\n2.times { probe.ready? }\np probe.calls<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list rpt-options\">\n<li>A. 1<\/li>\n\n\n\n<li>B. 2<\/li>\n\n\n\n<li>C. 0<\/li>\n\n\n\n<li>D. It raises NameError<\/li>\n<\/ul>\n\n\n\n<details class=\"wp-block-details rpt-explanation is-layout-flow wp-block-details-is-layout-flow\"><summary>Show answer and explanation<\/summary>\n<p class=\"wp-block-paragraph\"><strong>Answer B.<\/strong> The calculation is performed twice. Its first result is false, which causes the right-hand side of ||= to run again on the second call to ready?. To memoise a result that may be false or nil, record separately whether the calculation has happened.<\/p>\n<\/details>\n<\/div>\n\n\n\n<div class=\"wp-block-group rpt-question rpt-topic-debugging rpt-level-hard rpt-answer-0 is-layout-constrained wp-block-group-is-layout-constrained\">\n<p class=\"rpt-topic wp-block-paragraph\">Debugging<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">An explicit return in ensure<\/h4>\n\n\n\n<p class=\"rpt-prompt wp-block-paragraph\">Which return wins?<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>def value\n  return 1\nensure\n  return 2\nend\np value<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list rpt-options\">\n<li>A. 2<\/li>\n\n\n\n<li>B. 1<\/li>\n\n\n\n<li>C. nil<\/li>\n\n\n\n<li>D. It raises SyntaxError<\/li>\n<\/ul>\n\n\n\n<details class=\"wp-block-details rpt-explanation is-layout-flow wp-block-details-is-layout-flow\"><summary>Show answer and explanation<\/summary>\n<p class=\"wp-block-paragraph\"><strong>Answer A.<\/strong> The later explicit return takes effect, so value returns 2 to its caller. A return inside ensure can replace a pending result and can also suppress a pending exception. Keep cleanup clauses free of explicit returns unless you deliberately need that behavior.<\/p>\n<\/details>\n<\/div>\n\n\n\n<div class=\"wp-block-group rpt-question rpt-topic-collections rpt-level-hard rpt-answer-2 is-layout-constrained wp-block-group-is-layout-constrained\">\n<p class=\"rpt-topic wp-block-paragraph\">Collections<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Rebinding an immutable accumulator<\/h4>\n\n\n\n<p class=\"rpt-prompt wp-block-paragraph\">What does each_with_object return here?<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>result = &#91;1, 2, 3].each_with_object(0) do |number, total|\n  total += number\nend\np result<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list rpt-options\">\n<li>A. 6<\/li>\n\n\n\n<li>B. [1, 2, 3]<\/li>\n\n\n\n<li>C. 0<\/li>\n\n\n\n<li>D. 3<\/li>\n<\/ul>\n\n\n\n<details class=\"wp-block-details rpt-explanation is-layout-flow wp-block-details-is-layout-flow\"><summary>Show answer and explanation<\/summary>\n<p class=\"wp-block-paragraph\"><strong>Answer C.<\/strong> The result is still 0. total += number creates another Integer and rebinds the block&#8217;s local variable to it. The original accumulator remains unchanged. Consider reduce when the value from each iteration should become the accumulator for the next one.<\/p>\n<\/details>\n<\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Extra Hard Ruby programming test<\/h3>\n\n\n\n<div class=\"wp-block-group rpt-question rpt-topic-methods rpt-level-extra-hard rpt-answer-3 is-layout-constrained wp-block-group-is-layout-constrained\">\n<p class=\"rpt-topic wp-block-paragraph\">Methods<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Closures over one changing variable<\/h4>\n\n\n\n<p class=\"rpt-prompt wp-block-paragraph\">Which values do the saved lambdas return?<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>tasks = &#91;]\ni = 0\nwhile i &lt; 3\n  tasks &lt;&lt; -&gt; { i }\n  i += 1\nend\np tasks.map(&amp;:call)<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list rpt-options\">\n<li>A. [0, 1, 2]<\/li>\n\n\n\n<li>B. [1, 2, 3]<\/li>\n\n\n\n<li>C. [nil, nil, nil]<\/li>\n\n\n\n<li>D. [3, 3, 3]<\/li>\n<\/ul>\n\n\n\n<details class=\"wp-block-details rpt-explanation is-layout-flow wp-block-details-is-layout-flow\"><summary>Show answer and explanation<\/summary>\n<p class=\"wp-block-paragraph\"><strong>Answer D.<\/strong> All three calls read i after the loop, when it is 3. The lambdas share that captured variable rather than storing a snapshot of its earlier value. No per-iteration captured value was created here.<\/p>\n<\/details>\n<\/div>\n\n\n\n<div class=\"wp-block-group rpt-question rpt-topic-methods rpt-level-extra-hard rpt-answer-2 is-layout-constrained wp-block-group-is-layout-constrained\">\n<p class=\"rpt-topic wp-block-paragraph\">Methods<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">A Proc returning after its method has finished<\/h4>\n\n\n\n<p class=\"rpt-prompt wp-block-paragraph\">What happens when the saved Proc is called?<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>def build_handler\n  proc { return :done }\nend\nhandler = build_handler\nbegin\n  p handler.call\nrescue LocalJumpError\n  puts \"no active method\"\nend<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list rpt-options\">\n<li>A. It prints :done<\/li>\n\n\n\n<li>B. It prints nil<\/li>\n\n\n\n<li>C. It prints no active method<\/li>\n\n\n\n<li>D. It returns from the whole script normally<\/li>\n<\/ul>\n\n\n\n<details class=\"wp-block-details rpt-explanation is-layout-flow wp-block-details-is-layout-flow\"><summary>Show answer and explanation<\/summary>\n<p class=\"wp-block-paragraph\"><strong>Answer C.<\/strong> build_handler has already returned when handler.call runs. The Proc&#8217;s return tries to leave that finished method invocation and raises LocalJumpError, which the rescue handles. A return inside a lambda would leave the lambda itself.<\/p>\n<\/details>\n<\/div>\n\n\n\n<div class=\"wp-block-group rpt-question rpt-topic-collections rpt-level-extra-hard rpt-answer-0 is-layout-constrained wp-block-group-is-layout-constrained\">\n<p class=\"rpt-topic wp-block-paragraph\">Collections<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Stopping a lazy pipeline<\/h4>\n\n\n\n<p class=\"rpt-prompt wp-block-paragraph\">How many source values are processed?<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>seen = 0\nvalues = (1..).lazy.map do |number|\n  seen += 1\n  number * 2\nend.take(3).force\np &#91;values, seen]<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list rpt-options\">\n<li>A. [[2, 4, 6], 3]<\/li>\n\n\n\n<li>B. [[2, 4, 6], 4]<\/li>\n\n\n\n<li>C. It never terminates<\/li>\n\n\n\n<li>D. [[1, 2, 3], 3]<\/li>\n<\/ul>\n\n\n\n<details class=\"wp-block-details rpt-explanation is-layout-flow wp-block-details-is-layout-flow\"><summary>Show answer and explanation<\/summary>\n<p class=\"wp-block-paragraph\"><strong>Answer A.<\/strong> Only three source values pass through the mapping block. Lazy evaluation lets take(3) request just enough work before force collects [2, 4, 6]. An eager map over the endless range would have no finishing point.<\/p>\n<\/details>\n<\/div>\n\n\n\n<div class=\"wp-block-group rpt-question rpt-topic-debugging rpt-level-extra-hard rpt-answer-1 is-layout-constrained wp-block-group-is-layout-constrained\">\n<p class=\"rpt-topic wp-block-paragraph\">Debugging<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">String anchors versus line anchors<\/h4>\n\n\n\n<p class=\"rpt-prompt wp-block-paragraph\">How do the two expressions handle the trailing newline?<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>text = \"12\\n\"\np &#91;\/\\A&#91;0-9]+\\z\/.match?(text), \/^&#91;0-9]+$\/.match?(text)]<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list rpt-options\">\n<li>A. [true, true]<\/li>\n\n\n\n<li>B. [false, true]<\/li>\n\n\n\n<li>C. [true, false]<\/li>\n\n\n\n<li>D. [false, false]<\/li>\n<\/ul>\n\n\n\n<details class=\"wp-block-details rpt-explanation is-layout-flow wp-block-details-is-layout-flow\"><summary>Show answer and explanation<\/summary>\n<p class=\"wp-block-paragraph\"><strong>Answer B.<\/strong> The newline makes the whole-string pattern fail. The line-based pattern can still match the digits before that newline, so its result is true. For validation of an entire input string, use absolute string anchors rather than line boundaries.<\/p>\n<\/details>\n<\/div>\n\n\n\n<div class=\"wp-block-group rpt-question rpt-topic-methods rpt-level-extra-hard rpt-answer-3 is-layout-constrained wp-block-group-is-layout-constrained\">\n<p class=\"rpt-topic wp-block-paragraph\">Methods<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">A positional Hash is not a keyword argument<\/h4>\n\n\n\n<p class=\"rpt-prompt wp-block-paragraph\">Under Ruby 3.2&#8217;s argument rules, which output appears?<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>def quantity(limit:)\n  limit\nend\noptions = { limit: 3 }\nbegin\n  p quantity(options)\nrescue ArgumentError\n  puts \"use keyword expansion\"\nend<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list rpt-options\">\n<li>A. 3<\/li>\n\n\n\n<li>B. nil<\/li>\n\n\n\n<li>C. It raises KeyError<\/li>\n\n\n\n<li>D. use keyword expansion<\/li>\n<\/ul>\n\n\n\n<details class=\"wp-block-details rpt-explanation is-layout-flow wp-block-details-is-layout-flow\"><summary>Show answer and explanation<\/summary>\n<p class=\"wp-block-paragraph\"><strong>Answer D.<\/strong> options is passed as a positional Hash, while quantity expects a keyword. Ruby 3.2 raises ArgumentError for this call. quantity(**options) is the keyword expansion that would pass limit: 3 correctly.<\/p>\n<\/details>\n<\/div>\n\n\n\n<div class=\"wp-block-group rpt-question rpt-topic-methods rpt-level-extra-hard rpt-answer-1 is-layout-constrained wp-block-group-is-layout-constrained\">\n<p class=\"rpt-topic wp-block-paragraph\">Methods<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Qualified class syntax and constant lookup<\/h4>\n\n\n\n<p class=\"rpt-prompt wp-block-paragraph\">Which LABEL does this method find?<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>module Outer\n  LABEL = \"outer\"\nend\nclass Parent\n  LABEL = \"parent\"\nend\nclass Outer::Child &lt; Parent\n  def label\n    LABEL\n  end\nend\nputs Outer::Child.new.label<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list rpt-options\">\n<li>A. outer<\/li>\n\n\n\n<li>B. parent<\/li>\n\n\n\n<li>C. It raises NameError<\/li>\n\n\n\n<li>D. Outer::Child<\/li>\n<\/ul>\n\n\n\n<details class=\"wp-block-details rpt-explanation is-layout-flow wp-block-details-is-layout-flow\"><summary>Show answer and explanation<\/summary>\n<p class=\"wp-block-paragraph\"><strong>Answer B.<\/strong> The inherited LABEL in Parent is found, giving parent. Writing class Outer::Child does not establish the same lexical nesting as opening module Outer and defining Child inside it. A class&#8217;s qualified name alone does not describe its constant lookup context.<\/p>\n<\/details>\n<\/div>\n\n\n\n<div class=\"wp-block-group rpt-question rpt-topic-methods rpt-level-extra-hard rpt-answer-2 is-layout-constrained wp-block-group-is-layout-constrained\">\n<p class=\"rpt-topic wp-block-paragraph\">Methods<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Refinements and the call site<\/h4>\n\n\n\n<p class=\"rpt-prompt wp-block-paragraph\">Which pair of greetings is printed?<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>class Greeter\n  def greeting\n    \"hello\"\n  end\nend\nmodule Loud\n  refine Greeter do\n    def greeting\n      \"HELLO\"\n    end\n  end\nend\ndef earlier(object)\n  object.greeting\nend\nusing Loud\ngreeter = Greeter.new\np &#91;greeter.greeting, earlier(greeter)]<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list rpt-options\">\n<li>A. [&#8220;HELLO&#8221;, &#8220;HELLO&#8221;]<\/li>\n\n\n\n<li>B. [&#8220;hello&#8221;, &#8220;hello&#8221;]<\/li>\n\n\n\n<li>C. [&#8220;HELLO&#8221;, &#8220;hello&#8221;]<\/li>\n\n\n\n<li>D. [&#8220;hello&#8221;, &#8220;HELLO&#8221;]<\/li>\n<\/ul>\n\n\n\n<details class=\"wp-block-details rpt-explanation is-layout-flow wp-block-details-is-layout-flow\"><summary>Show answer and explanation<\/summary>\n<p class=\"wp-block-paragraph\"><strong>Answer C.<\/strong> The direct call uses the refinement and says HELLO. earlier was defined before using Loud, so its call retains the earlier refinement context and says hello. Sending the same object into a method does not carry the caller&#8217;s active refinements with it.<\/p>\n<\/details>\n<\/div>\n\n\n\n<div class=\"wp-block-group rpt-question rpt-topic-methods rpt-level-extra-hard rpt-answer-0 is-layout-constrained wp-block-group-is-layout-constrained\">\n<p class=\"rpt-topic wp-block-paragraph\">Methods<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Two included modules and super<\/h4>\n\n\n\n<p class=\"rpt-prompt wp-block-paragraph\">What is the method lookup order in the result?<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>module First\n  def chain\n    &#91;\"first\"] + super\n  end\nend\nmodule Second\n  def chain\n    &#91;\"second\"] + super\n  end\nend\nclass Base\n  def chain\n    &#91;\"base\"]\n  end\nend\nclass Child &lt; Base\n  include First\n  include Second\nend\np Child.new.chain<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list rpt-options\">\n<li>A. [&#8220;second&#8221;, &#8220;first&#8221;, &#8220;base&#8221;]<\/li>\n\n\n\n<li>B. [&#8220;first&#8221;, &#8220;second&#8221;, &#8220;base&#8221;]<\/li>\n\n\n\n<li>C. [&#8220;base&#8221;, &#8220;first&#8221;, &#8220;second&#8221;]<\/li>\n\n\n\n<li>D. It raises NoMethodError<\/li>\n<\/ul>\n\n\n\n<details class=\"wp-block-details rpt-explanation is-layout-flow wp-block-details-is-layout-flow\"><summary>Show answer and explanation<\/summary>\n<p class=\"wp-block-paragraph\"><strong>Answer A.<\/strong> Second was included last, so it contributes first. Its super reaches First, whose super reaches Base. The resulting array records that order as second, first, base.<\/p>\n<\/details>\n<\/div>\n\n\n\n<div class=\"wp-block-group rpt-question rpt-topic-debugging rpt-level-extra-hard rpt-answer-3 is-layout-constrained wp-block-group-is-layout-constrained\">\n<p class=\"rpt-topic wp-block-paragraph\">Debugging<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Exact keys in a Hash pattern<\/h4>\n\n\n\n<p class=\"rpt-prompt wp-block-paragraph\">Which branch matches this record?<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>record = { id: 7, extra: true }\ncase record\nin { id: Integer =&gt; id, **nil }\n  puts \"exact keys\"\nin { id: Integer =&gt; id }\n  puts \"contains #{id}\"\nend<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list rpt-options\">\n<li>A. exact keys<\/li>\n\n\n\n<li>B. Both branches<\/li>\n\n\n\n<li>C. It raises NoMatchingPatternError<\/li>\n\n\n\n<li>D. contains 7<\/li>\n<\/ul>\n\n\n\n<details class=\"wp-block-details rpt-explanation is-layout-flow wp-block-details-is-layout-flow\"><summary>Show answer and explanation<\/summary>\n<p class=\"wp-block-paragraph\"><strong>Answer D.<\/strong> The extra key prevents the first pattern from matching: **nil forbids unlisted keys. The second pattern allows extras, requires an Integer :id and captures 7. That branch prints contains 7.<\/p>\n<\/details>\n<\/div>\n\n\n\n<div class=\"wp-block-group rpt-question rpt-topic-collections rpt-level-extra-hard rpt-answer-1 is-layout-constrained wp-block-group-is-layout-constrained\">\n<p class=\"rpt-topic wp-block-paragraph\">Collections<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Identity-based Hash keys<\/h4>\n\n\n\n<p class=\"rpt-prompt wp-block-paragraph\">What happens to equal but distinct String objects?<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># frozen_string_literal: false\na = \"ruby\"\nb = \"ruby\"\nlookup = {}.compare_by_identity\nlookup&#91;a] = 1\nlookup&#91;b] = 2\np &#91;lookup.size, lookup&#91;a], lookup&#91;\"ruby\"]]<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list rpt-options\">\n<li>A. [1, 2, 2]<\/li>\n\n\n\n<li>B. [2, 1, nil]<\/li>\n\n\n\n<li>C. [2, 2, 2]<\/li>\n\n\n\n<li>D. [1, 1, 1]<\/li>\n<\/ul>\n\n\n\n<details class=\"wp-block-details rpt-explanation is-layout-flow wp-block-details-is-layout-flow\"><summary>Show answer and explanation<\/summary>\n<p class=\"wp-block-paragraph\"><strong>Answer B.<\/strong> There are two entries because a and b are distinct objects. This identity-based Hash finds the original a, but the third String created during lookup is a different key and returns nil. Equal text is not enough when key identity is the comparison rule.<\/p>\n<\/details>\n<\/div>\n<\/div>\n<\/div>\n\n\n\n<h2 class=\"wp-block-heading\">How to read your Ruby programming test results<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">A result is most useful when it tells you what to do next. Look through the missed answers and find one you can explain now. If the explanation still feels mysterious, copy its snippet into a small Ruby file and trace it one line at a time. The topic breakdown helps you spot where several mistakes have a common cause.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For this question bank, use 80\u2013100% as a sign that most tested ideas are familiar, 50\u201379% as a prompt for focused practice and below 50% as a reason to revisit the foundations of that level. These are informal study bands. Compare Newbie attempts with Newbie and Extra Hard attempts with Extra Hard: the material is different, and a small topic score is only a limited sample.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Retrying missed and unanswered questions starts a fresh practice attempt with a smaller set. A higher score can show that an explanation helped, but you have also seen those questions before. Return to the full level later if you want a more useful comparison with your first attempt.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Turn a missed answer into a useful experiment<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Choose a small example you misunderstood and change one thing. Swap map for each, replace a String key with a Symbol key, or remove the default from fetch. Write down your prediction before you run it. Comparing that prediction with the output gives you a specific mistake to investigate.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For additional exercises, work through our <a href=\"https:\/\/ruby-doc.org\/learn\/ruby-code-examples\/\">practical Ruby code examples<\/a>. If transformations and blocks need more attention, the <a href=\"https:\/\/ruby-doc.org\/learn\/ruby-functional-programming\/\">Ruby functional programming guide<\/a> connects those ideas in longer examples.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Use the official Ruby Array reference to check indexing, map, select and compact. The official Ruby Hash reference explains key lookup and fetch. Both links point to Ruby 3.4 documentation, making the reference version explicit.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Four Ruby coding challenges: one for each level<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">For the coding challenges, start with the contract: what input is allowed, what output is required and what must stay unchanged. Draft your method in the scratchpad, then copy it into a local Ruby file with the supplied checks. The scratchpad neither executes Ruby nor saves your work. A worked solution is there when you want to compare approaches.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Keep going after the supplied example works. An empty array, repeated value or malformed argument can expose an assumption you missed. Use the checks as a starting point, add a case of your own and explain which error that case would catch.<\/p>\n\n\n\n<div class=\"wp-block-group rpt-challenge is-layout-constrained wp-block-group-is-layout-constrained\">\n<h3 class=\"wp-block-heading\">Newbie challenge: Keep the unique positive integers<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Given an Array of Integers, return a new array containing only positive values, without duplicates, in their original order. Do not modify the input. Assume the input already meets the stated type contract.<\/p>\n\n\n\n<div class=\"wp-block-group rpt-starter is-layout-constrained wp-block-group-is-layout-constrained\">\n<pre class=\"wp-block-code\"><code>def unique_positive(numbers)\n  # Return a new array.\nend<\/code><\/pre>\n<\/div>\n\n\n\n<h4 class=\"wp-block-heading\">Checks to run with your method<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code>input = &#91;-2, 3, 0, 3, 5, -1]\nraise \"values\" unless unique_positive(input) == &#91;3, 5]\nraise \"empty\" unless unique_positive(&#91;]) == &#91;]\nraise \"order\" unless unique_positive(&#91;5, 2, 5, 1]) == &#91;5, 2, 1]\nraise \"input changed\" unless input == &#91;-2, 3, 0, 3, 5, -1]\nputs \"Challenge 1 checks passed\"<\/code><\/pre>\n\n\n\n<details class=\"wp-block-details rpt-solution is-layout-flow wp-block-details-is-layout-flow\"><summary>Show worked solution<\/summary>\n<pre class=\"wp-block-code\"><code>def unique_positive(numbers)\n  numbers.select { |n| n.positive? }.uniq\nend<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">select expresses the positive-value rule, and uniq removes later repetitions while preserving the first occurrence. Both calls here return new arrays. The mutation check compares the original input after the method call.<\/p>\n<\/details>\n<\/div>\n\n\n\n<div class=\"wp-block-group rpt-challenge is-layout-constrained wp-block-group-is-layout-constrained\">\n<h3 class=\"wp-block-heading\">Medium challenge: Count normalised labels<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Given an Array of Strings, strip surrounding whitespace, convert each string to lowercase, skip empty results and count each remaining label in a Hash. Do not modify the input strings. Assume all input elements are Strings; these examples use ASCII text.<\/p>\n\n\n\n<div class=\"wp-block-group rpt-starter is-layout-constrained wp-block-group-is-layout-constrained\">\n<pre class=\"wp-block-code\"><code>def label_counts(labels)\n  # Return a hash of normalised labels and counts.\nend<\/code><\/pre>\n<\/div>\n\n\n\n<h4 class=\"wp-block-heading\">Checks to run with your method<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code>input = &#91;\" Ruby \", \"ruby\", \"\", \"SWIFT\", \"  \"]\nraise \"counts\" unless label_counts(input) == { \"ruby\" =&gt; 2, \"swift\" =&gt; 1 }\nraise \"empty\" unless label_counts(&#91;]) == {}\nraise \"input changed\" unless input.first == \" Ruby \"\nraise \"separate calls\" unless label_counts(&#91;\"Ruby\"]) == { \"ruby\" =&gt; 1 }\nputs \"Challenge 2 checks passed\"<\/code><\/pre>\n\n\n\n<details class=\"wp-block-details rpt-solution is-layout-flow wp-block-details-is-layout-flow\"><summary>Show worked solution<\/summary>\n<pre class=\"wp-block-code\"><code>def label_counts(labels)\n  labels.each_with_object(Hash.new(0)) do |label, counts|\n    key = label.strip.downcase\n    counts&#91;key] += 1 unless key.empty?\n  end\nend<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The accumulator belongs to this method call. Hash.new(0) supplies zero for an unseen label, while += writes the updated count. strip and downcase create the cleaned string here, leaving the caller&#8217;s original text intact.<\/p>\n<\/details>\n<\/div>\n\n\n\n<div class=\"wp-block-group rpt-challenge is-layout-constrained wp-block-group-is-layout-constrained\">\n<h3 class=\"wp-block-heading\">Hard challenge: Validate a small quantity<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Accept only a String containing one or two ASCII decimal digits whose numeric value is between 1 and 20 inclusive. Return the Integer value, or nil for anything else. Reject surrounding whitespace, signs and trailing text. Under this contract, &#8220;01&#8221; is accepted as 1.<\/p>\n\n\n\n<div class=\"wp-block-group rpt-starter is-layout-constrained wp-block-group-is-layout-constrained\">\n<pre class=\"wp-block-code\"><code>def parse_quantity(value)\n  # Return an integer from 1 to 20, or nil.\nend<\/code><\/pre>\n<\/div>\n\n\n\n<h4 class=\"wp-block-heading\">Checks to run with your method<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code>raise \"lower bound\" unless parse_quantity(\"1\") == 1\nraise \"upper bound\" unless parse_quantity(\"20\") == 20\nraise \"leading zero\" unless parse_quantity(\"01\") == 1\n&#91;\"0\", \"21\", \" 2\", \"2 \", \"2cats\", \"+2\", \"2\\n\", \"001\", \"\", nil, 2].each do |bad|\n  raise \"accepted #{bad.inspect}\" unless parse_quantity(bad).nil?\nend\nputs \"Challenge 3 checks passed\"<\/code><\/pre>\n\n\n\n<details class=\"wp-block-details rpt-solution is-layout-flow wp-block-details-is-layout-flow\"><summary>Show worked solution<\/summary>\n<pre class=\"wp-block-code\"><code>def parse_quantity(value)\n  return nil unless value.is_a?(String)\n  return nil unless \/\\A&#91;0-9]{1,2}\\z\/.match?(value)\n\n  number = Integer(value, 10)\n  (1..20).cover?(number) ? number : nil\nend<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The type check runs before the regular expression. The absolute string anchors require the entire string to contain just one or two ASCII digits, and the final range check enforces the business limit. Specifying base 10 keeps the leading-zero case unambiguous.<\/p>\n<\/details>\n<\/div>\n\n\n\n<div class=\"wp-block-group rpt-challenge is-layout-constrained wp-block-group-is-layout-constrained\">\n<h3 class=\"wp-block-heading\">Extra Hard challenge: Stop a lazy event stream at the right time<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Given an Enumerable of mixed objects and a nonnegative Integer limit, return the first limit distinct positive Integer IDs from Hash events whose :active value is exactly true. Ignore other events. Preserve encounter order and do not consume more source events after enough IDs have been collected. A zero limit must consume nothing; an invalid limit must raise ArgumentError.<\/p>\n\n\n\n<div class=\"wp-block-group rpt-starter is-layout-constrained wp-block-group-is-layout-constrained\">\n<pre class=\"wp-block-code\"><code>def first_valid_ids(events, limit:)\n  # Filter lazily and stop once the requested IDs are found.\nend<\/code><\/pre>\n<\/div>\n\n\n\n<h4 class=\"wp-block-heading\">Checks to run with your method<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code>seen = 0\nsource = &#91;nil, { id: 2, active: true }, { id: 2, active: true },\n          { id: 3, active: false }, { id: 4, active: true },\n          { id: 9, active: true }].lazy.map { |event| seen += 1; event }\nraise \"IDs\" unless first_valid_ids(source, limit: 2) == &#91;2, 4]\nraise \"over-consumed\" unless seen == 5\nnever = Enumerator.new { raise \"must not consume\" }\nraise \"zero\" unless first_valid_ids(never, limit: 0) == &#91;]\nraise \"empty\" unless first_valid_ids(&#91;], limit: 3) == &#91;]\nraise \"invalid event\" unless first_valid_ids(&#91;{ id: \"2\", active: true },\n  { id: 0, active: true }, { id: 3, active: 1 }], limit: 3) == &#91;]\nbegin\n  first_valid_ids(&#91;], limit: -1)\n  raise \"negative limit accepted\"\nrescue ArgumentError\n  # Expected.\nend\nputs \"Challenge 4 checks passed\"<\/code><\/pre>\n\n\n\n<details class=\"wp-block-details rpt-solution is-layout-flow wp-block-details-is-layout-flow\"><summary>Show worked solution<\/summary>\n<pre class=\"wp-block-code\"><code>def first_valid_ids(events, limit:)\n  unless limit.is_a?(Integer) &amp;&amp; limit &gt;= 0\n    raise ArgumentError, \"limit must be a nonnegative Integer\"\n  end\n\n  events.lazy.filter_map do |event|\n    next unless event.is_a?(Hash) &amp;&amp; event&#91;:active] == true\n    id = event&#91;:id]\n    id if id.is_a?(Integer) &amp;&amp; id.positive?\n  end.uniq.take(limit).force\nend<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The lazy chain validates events before collecting IDs. uniq remembers IDs already seen, and take limits how many unique IDs are requested. The counter check catches accidental eager evaluation or reading past the second unique valid ID. The zero-limit check uses an Enumerator that would raise if touched.<\/p>\n<\/details>\n<\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Ruby programming test: common questions<\/h2>\n\n\n\n<details class=\"wp-block-details rdc-disclosure is-layout-flow wp-block-details-is-layout-flow\"><summary>Is this Ruby programming test suitable for beginners?<\/summary>\n<p class=\"wp-block-paragraph\">Yes. Choose Newbie for ten questions on basic Ruby behavior and use practice mode to see feedback as you go. Medium, Hard and Extra Hard provide separate sets when you want a greater challenge.<\/p>\n<\/details>\n\n\n\n<details class=\"wp-block-details rdc-disclosure is-layout-flow wp-block-details-is-layout-flow\"><summary>Do I need to install Ruby to take the quiz?<\/summary>\n<p class=\"wp-block-paragraph\">No installation is needed for the multiple-choice quiz. To run your own solutions and the supplied challenge checks, use a local Ruby installation. The page scores selected answers; it does not execute arbitrary Ruby code.<\/p>\n<\/details>\n\n\n\n<details class=\"wp-block-details rdc-disclosure is-layout-flow wp-block-details-is-layout-flow\"><summary>Can I use the score to prepare for an interview?<\/summary>\n<p class=\"wp-block-paragraph\">Use it to identify topics to practise before an interview. Also write and explain programs, discuss trade-offs and debug unfamiliar code. A score on this short question bank cannot establish job readiness.<\/p>\n<\/details>\n\n\n\n<details class=\"wp-block-details rdc-disclosure is-layout-flow wp-block-details-is-layout-flow\"><summary>Can I retake the test?<\/summary>\n<p class=\"wp-block-paragraph\">Yes. Choose any level again, shuffle its question order, attempt all 40 questions or retry only missed and unanswered items. Your saved attempt stays in this browser, and the reset control clears it.<\/p>\n<\/details>\n\n\n\n<h2 class=\"wp-block-heading\">About this Ruby programming test<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">All 40 question snippets and the four worked challenge solutions were executed with Ruby 3.2.3. The linked references use Ruby 3.4. The test concerns core Ruby; individual questions state assumptions where they matter.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Choose one of four Ruby test levels, each with ten questions, scored practice and exam modes, clear explanations and a matching coding challenge.<\/p>\n","protected":false},"author":3,"featured_media":1628,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4],"tags":[],"class_list":["post-1630","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-programming"],"blocksy_meta":{"styles_descriptor":{"styles":{"desktop":"","tablet":"","mobile":""},"google_fonts":[],"version":7}},"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.4 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Ruby Programming Test: 4 Levels, 40 Questions<\/title>\n<meta name=\"description\" content=\"Take a free Ruby programming test at newbie, medium, hard or extra hard level. Get scored results, explanations &amp; four coding challenges.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/ruby-doc.org\/learn\/ruby-programming-test\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Ruby Programming Test: 4 Levels, 40 Questions\" \/>\n<meta property=\"og:description\" content=\"Take a free Ruby programming test at newbie, medium, hard or extra hard level. Get scored results, explanations &amp; four coding challenges.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/ruby-doc.org\/learn\/ruby-programming-test\/\" \/>\n<meta property=\"og:site_name\" content=\"Ruby-Doc Learn\" \/>\n<meta property=\"article:published_time\" content=\"2026-09-14T10:05:40+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-09-14T11:05:19+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/ruby-doc.org\/learn\/wp-content\/uploads\/2026\/09\/ruby-programming-test-featured.webp\" \/>\n\t<meta property=\"og:image:width\" content=\"1536\" \/>\n\t<meta property=\"og:image:height\" content=\"1024\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/webp\" \/>\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=\"19 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/ruby-doc.org\\\/learn\\\/ruby-programming-test\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/ruby-doc.org\\\/learn\\\/ruby-programming-test\\\/\"},\"author\":{\"@id\":\"https:\\\/\\\/ruby-doc.org\\\/learn\\\/james-britt\\\/#james-britt\"},\"headline\":\"Ruby Programming Test: Newbie, Medium, Hard and Extra Hard\",\"datePublished\":\"2026-09-14T10:05:40+00:00\",\"dateModified\":\"2026-09-14T11:05:19+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/ruby-doc.org\\\/learn\\\/ruby-programming-test\\\/\"},\"wordCount\":4038,\"publisher\":{\"@id\":\"https:\\\/\\\/ruby-doc.org\\\/learn\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/ruby-doc.org\\\/learn\\\/ruby-programming-test\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/ruby-doc.org\\\/learn\\\/wp-content\\\/uploads\\\/2026\\\/09\\\/ruby-programming-test-featured.webp\",\"articleSection\":[\"Programming\"],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/ruby-doc.org\\\/learn\\\/ruby-programming-test\\\/\",\"url\":\"https:\\\/\\\/ruby-doc.org\\\/learn\\\/ruby-programming-test\\\/\",\"name\":\"Ruby Programming Test: 4 Levels, 40 Questions\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/ruby-doc.org\\\/learn\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/ruby-doc.org\\\/learn\\\/ruby-programming-test\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/ruby-doc.org\\\/learn\\\/ruby-programming-test\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/ruby-doc.org\\\/learn\\\/wp-content\\\/uploads\\\/2026\\\/09\\\/ruby-programming-test-featured.webp\",\"datePublished\":\"2026-09-14T10:05:40+00:00\",\"dateModified\":\"2026-09-14T11:05:19+00:00\",\"description\":\"Take a free Ruby programming test at newbie, medium, hard or extra hard level. Get scored results, explanations & four coding challenges.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/ruby-doc.org\\\/learn\\\/ruby-programming-test\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/ruby-doc.org\\\/learn\\\/ruby-programming-test\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/ruby-doc.org\\\/learn\\\/ruby-programming-test\\\/#primaryimage\",\"url\":\"https:\\\/\\\/ruby-doc.org\\\/learn\\\/wp-content\\\/uploads\\\/2026\\\/09\\\/ruby-programming-test-featured.webp\",\"contentUrl\":\"https:\\\/\\\/ruby-doc.org\\\/learn\\\/wp-content\\\/uploads\\\/2026\\\/09\\\/ruby-programming-test-featured.webp\",\"width\":1536,\"height\":1024,\"caption\":\"Practise Ruby concepts, check your reasoning and work through code challenges.\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/ruby-doc.org\\\/learn\\\/ruby-programming-test\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/ruby-doc.org\\\/learn\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Ruby Programming Test: Newbie, Medium, Hard and Extra Hard\"}]},{\"@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":"Ruby Programming Test: 4 Levels, 40 Questions","description":"Take a free Ruby programming test at newbie, medium, hard or extra hard level. Get scored results, explanations & four coding challenges.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/ruby-doc.org\/learn\/ruby-programming-test\/","og_locale":"en_US","og_type":"article","og_title":"Ruby Programming Test: 4 Levels, 40 Questions","og_description":"Take a free Ruby programming test at newbie, medium, hard or extra hard level. Get scored results, explanations & four coding challenges.","og_url":"https:\/\/ruby-doc.org\/learn\/ruby-programming-test\/","og_site_name":"Ruby-Doc Learn","article_published_time":"2026-09-14T10:05:40+00:00","article_modified_time":"2026-09-14T11:05:19+00:00","og_image":[{"width":1536,"height":1024,"url":"https:\/\/ruby-doc.org\/learn\/wp-content\/uploads\/2026\/09\/ruby-programming-test-featured.webp","type":"image\/webp"}],"author":"James Britt","twitter_card":"summary_large_image","twitter_misc":{"Written by":"James Britt","Est. reading time":"19 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/ruby-doc.org\/learn\/ruby-programming-test\/#article","isPartOf":{"@id":"https:\/\/ruby-doc.org\/learn\/ruby-programming-test\/"},"author":{"@id":"https:\/\/ruby-doc.org\/learn\/james-britt\/#james-britt"},"headline":"Ruby Programming Test: Newbie, Medium, Hard and Extra Hard","datePublished":"2026-09-14T10:05:40+00:00","dateModified":"2026-09-14T11:05:19+00:00","mainEntityOfPage":{"@id":"https:\/\/ruby-doc.org\/learn\/ruby-programming-test\/"},"wordCount":4038,"publisher":{"@id":"https:\/\/ruby-doc.org\/learn\/#organization"},"image":{"@id":"https:\/\/ruby-doc.org\/learn\/ruby-programming-test\/#primaryimage"},"thumbnailUrl":"https:\/\/ruby-doc.org\/learn\/wp-content\/uploads\/2026\/09\/ruby-programming-test-featured.webp","articleSection":["Programming"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/ruby-doc.org\/learn\/ruby-programming-test\/","url":"https:\/\/ruby-doc.org\/learn\/ruby-programming-test\/","name":"Ruby Programming Test: 4 Levels, 40 Questions","isPartOf":{"@id":"https:\/\/ruby-doc.org\/learn\/#website"},"primaryImageOfPage":{"@id":"https:\/\/ruby-doc.org\/learn\/ruby-programming-test\/#primaryimage"},"image":{"@id":"https:\/\/ruby-doc.org\/learn\/ruby-programming-test\/#primaryimage"},"thumbnailUrl":"https:\/\/ruby-doc.org\/learn\/wp-content\/uploads\/2026\/09\/ruby-programming-test-featured.webp","datePublished":"2026-09-14T10:05:40+00:00","dateModified":"2026-09-14T11:05:19+00:00","description":"Take a free Ruby programming test at newbie, medium, hard or extra hard level. Get scored results, explanations & four coding challenges.","breadcrumb":{"@id":"https:\/\/ruby-doc.org\/learn\/ruby-programming-test\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/ruby-doc.org\/learn\/ruby-programming-test\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/ruby-doc.org\/learn\/ruby-programming-test\/#primaryimage","url":"https:\/\/ruby-doc.org\/learn\/wp-content\/uploads\/2026\/09\/ruby-programming-test-featured.webp","contentUrl":"https:\/\/ruby-doc.org\/learn\/wp-content\/uploads\/2026\/09\/ruby-programming-test-featured.webp","width":1536,"height":1024,"caption":"Practise Ruby concepts, check your reasoning and work through code challenges."},{"@type":"BreadcrumbList","@id":"https:\/\/ruby-doc.org\/learn\/ruby-programming-test\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/ruby-doc.org\/learn\/"},{"@type":"ListItem","position":2,"name":"Ruby Programming Test: Newbie, Medium, Hard and Extra Hard"}]},{"@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\/1630","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=1630"}],"version-history":[{"count":1,"href":"https:\/\/ruby-doc.org\/learn\/wp-json\/wp\/v2\/posts\/1630\/revisions"}],"predecessor-version":[{"id":1631,"href":"https:\/\/ruby-doc.org\/learn\/wp-json\/wp\/v2\/posts\/1630\/revisions\/1631"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/ruby-doc.org\/learn\/wp-json\/wp\/v2\/media\/1628"}],"wp:attachment":[{"href":"https:\/\/ruby-doc.org\/learn\/wp-json\/wp\/v2\/media?parent=1630"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ruby-doc.org\/learn\/wp-json\/wp\/v2\/categories?post=1630"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ruby-doc.org\/learn\/wp-json\/wp\/v2\/tags?post=1630"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}