<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:sy="http://purl.org/rss/1.0/modules/syndication/">
	<channel>
		<title>Author at Infinum</title>
		<atom:link href="https://infinum.com/blog/author/marko-cilimkovic/feed/" rel="self" type="application/rss+xml" />
		<link></link>
		<description>Building digital products</description>
		<lastBuildDate>Fri, 10 Apr 2026 14:51:20 +0000</lastBuildDate>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>

					<item>
				<image>
					<url>8013https://infinum.com/uploads/2020/12/code-quality-rubocop-0.webp</url>
				</image>
				<title>Improve Code Quality with RuboCop</title>
				<link>https://infinum.com/blog/code-quality-rubocop/</link>
				<pubDate>Fri, 11 Dec 2020 11:20:00 +0000</pubDate>
				<dc:creator>Marko Ćilimković</dc:creator>
				<guid isPermaLink="false">https://infinum.com/the-capsized-eight/code-quality-rubocop/</guid>
				<description>
					<![CDATA[<p>Cleaner pull requests, automated knowledge sharing, and easy engagement with open-source software? Sign me up!</p>
<p>The post <a href="https://infinum.com/blog/code-quality-rubocop/">Improve Code Quality with RuboCop</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</description>
				<content:encoded>
					<![CDATA[<div
	class="wrapper"
	data-id="es-340"
	 data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-blog-content js-block-blog-content">
	
<div class="block-blog-content-sidebar" data-id="es-92">
	</div>

<div class="block-blog-content-main">
	
<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-95"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-93">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-94'
	>
	Modern code reviews are considered a key component in the development lifecycle of any IT organization.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-98"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-96">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-97'
	>
	Yearly case studies performed by various researchers report that it’s one of the main methods for improving code quality, sharing knowledge across the team, increased collaboration as well as greater adherence to coding standards.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-101"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-99">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-100'
	>
	Unlike Fagan’s<a href="https://ieeexplore.ieee.org/document/5388086"> code inspection design</a> introduced in 1976, most of us employ a more lenient process, which is:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-104"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-102">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-103'
	>
	<li>informal</li><li>asynchronous</li><li>tool-based</li><li>focused on reviewing code changes</li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-107"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-105">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-106'
	>
	Results from multiple analysis have shown that the latent defect discovery rate is about 30% in case of informal reviews, proving them to be very effective. They are also a great source of knowledge, because the process usually entails multiple developers collectively looking at a problem and the possible solution.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-110"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-108">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-109'
	>
	However, code reviews can become quite cumbersome for newcomers, especially if you find yourself in a company that has some tribal knowledge, which is usually the case.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-113"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-111"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-112">
	<picture class="image__picture block-media__image-picture">
								
			<source
				srcset=https://infinum.com/uploads/2020/12/code-quality-rubocop-1-1400x1049.webp				media='(max-width: 699px)'
				type=image/webp								height="1049"
												width="1400"
				 />
												<img
					src="https://infinum.com/uploads/2020/12/code-quality-rubocop-1.webp"
					class="image__img block-media__image-img"
					alt=""
										height="1799"
															width="2400"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-116"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-114">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-115'
	>
	Tribal knowledge is any unwritten form of how a process should work, or in our specific case, how to produce code. And there can be quite <strong>a lot</strong> of it, spanning from syntax preferences to unwritten rules and established conventions, which in turn results in code reviews containing dozens of comments that could have been avoided.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-119"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-117">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-118'
	>
	That kind of noise takes a lot of focus from the business logic and design. It further elongates the code review process as each back and forth takes additional time due to the asynchronous nature of the process.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-122"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-120">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-121'
	>
	A solution to this problem are <strong>linters</strong> and if you chose Ruby as your programming language, chances are high that you already used <a href="https://rubocop.org/">RuboCop</a>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-125"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-123">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-124'
	>
	RuboCop linter</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-128"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-126">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-127'
	>
	Linters are tools used during development that warn the programmer about formatting and adhering to a set of rules.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-131"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-129">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-130'
	>
	The warnings are usually related to syntax, but the Ruby community went a step further and introduced a couple of behavioral ones like <a href="https://github.com/rubocop-hq/rubocop-rails">rubocop-rails</a> that can even spot unwanted behaviour for you.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-134"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-132">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-133'
	>
	If you think about it, why wouldn’t you want automatic warnings when you introduce a bug…before the code is shipped. It sounds amazing!</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-137"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-135">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-136'
	>
	A very cool behavioural cop is the <em>Rails/UniqueValidationWithoutIndex</em>, which detects model uniqueness validations and checks if the uniqueness constraints are also set on the database level. In the following example you can see how the warning looks like if you forget to add the unique index during database migrations.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-140"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-138"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-139">
	<picture class="image__picture block-media__image-picture">
								
			<source
				srcset=https://infinum.com/uploads/2020/12/code-quality-rubocop-2-1400x262.webp				media='(max-width: 699px)'
				type=image/webp								height="262"
												width="1400"
				 />
												<img
					src="https://infinum.com/uploads/2020/12/code-quality-rubocop-2.webp"
					class="image__img block-media__image-img"
					alt=""
										height="268"
															width="1434"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-143"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-141">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-142'
	>
	This concept opens up a lot of ideas and opportunities for a company to create a code convention template that is shared throughout all projects. This increases technical cohesion on a team level and ensures that everyone is roughly on the same page when it comes to conventions and best practices.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-146"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-144">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-145'
	>
	Let’s look at a specific code example in Rails that declares the attribute confirmed_at on a User and it defaults to the current time. The <a href="https://api.rubyonrails.org/classes/ActiveRecord/Attributes/ClassMethods.html#method-i-attribute">Attributes API</a> provides just what we need:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-148"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-ruby github-light" data-language="ruby" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #d73a49;">class</span><span class="token"> </span><span class="token" style="color: #6f42c1;">User</span><span class="token">
</span></span><span class="line"><span class="token">  attribute </span><span class="token" style="color: #005cc5;">:</span><span class="token" style="color: #005cc5;">confirmed_at</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #005cc5;">:</span><span class="token" style="color: #005cc5;">datetime</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #005cc5;">default</span><span class="token" style="color: #005cc5;">:</span><span class="token"> </span><span class="token" style="color: #005cc5;">Time</span><span class="token">.</span><span class="token" style="color: #6f42c1;">zone</span><span class="token">.</span><span class="token" style="color: #6f42c1;">now</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">end</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-150"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-ruby github-light" data-language="ruby" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">pry</span><span class="token" style="color: #d73a49;">&gt;</span><span class="token"> </span><span class="token" style="color: #005cc5;">User</span><span class="token">.</span><span class="token" style="color: #d73a49;">new</span><span class="token">
</span></span><span class="line"><span class="token">=&gt;</span><span class="token"> </span><span class="token" style="color: #6a737d;">#</span><span class="token" style="color: #6a737d;">&lt;User id: nil, confirmed_at: Tue, 27 Oct 2020 11:39:22 UTC +00:00</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-153"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-151">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-152'
	>
	At first glance, this looks totally fine, but if you don’t write thorough tests, the bug can be hard to catch, even during code reviews. Look at what happens for every new user:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-155"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-ruby github-light" data-language="ruby" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">pry</span><span class="token" style="color: #d73a49;">&gt;</span><span class="token"> </span><span class="token" style="color: #005cc5;">User</span><span class="token">.</span><span class="token" style="color: #d73a49;">new</span><span class="token">
</span></span><span class="line"><span class="token">=&gt;</span><span class="token"> </span><span class="token" style="color: #6a737d;">#</span><span class="token" style="color: #6a737d;">&lt;User id: nil, confirmed_at: Tue, 27 Oct 2020 11:39:22 UTC +00:00</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token">pry</span><span class="token" style="color: #d73a49;">&gt;</span><span class="token"> </span><span class="token" style="color: #005cc5;">User</span><span class="token">.</span><span class="token" style="color: #d73a49;">new</span><span class="token">
</span></span><span class="line"><span class="token">=&gt;</span><span class="token"> </span><span class="token" style="color: #6a737d;">#</span><span class="token" style="color: #6a737d;">&lt;User id: nil, confirmed_at: Tue, 27 Oct 2020 11:39:22 UTC +00:00</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token">pry</span><span class="token" style="color: #d73a49;">&gt;</span><span class="token"> </span><span class="token" style="color: #005cc5;">User</span><span class="token">.</span><span class="token" style="color: #d73a49;">new</span><span class="token">
</span></span><span class="line"><span class="token">=&gt;</span><span class="token"> </span><span class="token" style="color: #6a737d;">#</span><span class="token" style="color: #6a737d;">&lt;User id: nil, confirmed_at: Tue, 27 Oct 2020 11:39:22 UTC +00:00</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-158"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-156">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-157'
	>
	<em>Time.zone.now</em> is being passed as a value to the default option, and since attribute is a class method, the value of <em>Time.zone.now</em> is set at the moment when the application is booted. This means that all <strong>values</strong> will be the <strong>same</strong> regardless of the return value of <em>Time.zone.now</em> at the time of code execution.<br>The solution is defining <em>confirmed_at</em> dynamically:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-160"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-ruby github-light" data-language="ruby" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #d73a49;">class</span><span class="token"> </span><span class="token" style="color: #6f42c1;">User</span><span class="token">
</span></span><span class="line"><span class="token">  attribute </span><span class="token" style="color: #005cc5;">:</span><span class="token" style="color: #005cc5;">confirmed_at</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #005cc5;">:</span><span class="token" style="color: #005cc5;">datetime</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #005cc5;">default</span><span class="token" style="color: #005cc5;">:</span><span class="token"> </span><span class="token" style="color: #005cc5;">-&gt;</span><span class="token"> </span><span class="token">{</span><span class="token"> </span><span class="token" style="color: #005cc5;">Time</span><span class="token">.</span><span class="token" style="color: #6f42c1;">zone</span><span class="token">.</span><span class="token" style="color: #6f42c1;">now</span><span class="token"> </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">end</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-163"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-161">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-162'
	>
	This is a perfect example of tribal knowledge. You either learn to avoid it by breaking production, writing very thorough unit tests or by having someone more experienced mention it during the code review.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-166"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-164">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-165'
	>
	Now imagine someone’s watching over your code as you type it, without the awkward presence of course, and giving you real time feedback to avoid such pitfalls. This is exactly what RuboCop’s cops provide us with. In order to be able to build such a layer of protection, you first need to understand how the source code gets converted into data structures.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-169"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-167">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-168'
	>
	Abstract syntax tree</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-172"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-170">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-171'
	>
	AST is a <strong>tree representation</strong> of the written <strong>source code</strong>. Each node of the tree denotes a piece of the source code, which can be any literal, object, constant or any other construct used in the programming language.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-175"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-173">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-174'
	>
	Let’s take a look at some simple examples of Ruby constructs and how their AST looks like.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-178"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-176">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-177'
	>
	For this, the <a href="https://github.com/whitequark/parser">parser</a> gem is used. After installing it, you can jump into your terminal and start playing around:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-180"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-shellscript github-light" data-language="shellscript" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #6f42c1;">ruby-parse</span><span class="token"> </span><span class="token" style="color: #005cc5;">-</span><span class="token" style="color: #005cc5;">e</span><span class="token"> </span><span class="token">&amp;</span><span class="token">#8217;1&amp;#8217;
</span></span><span class="line"><span class="token">(</span><span class="token" style="color: #6f42c1;">int</span><span class="token"> </span><span class="token" style="color: #005cc5;">1</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #6f42c1;">ruby-parse</span><span class="token"> </span><span class="token" style="color: #005cc5;">-</span><span class="token" style="color: #005cc5;">e</span><span class="token"> </span><span class="token">&amp;</span><span class="token">#8217;”1”&amp;#8217;
</span></span><span class="line"><span class="token">(</span><span class="token" style="color: #6f42c1;">str</span><span class="token"> </span><span class="token" style="color: #032f62;">“1”)
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #6f42c1;">ruby-parse</span><span class="token"> </span><span class="token" style="color: #005cc5;">-</span><span class="token" style="color: #005cc5;">e</span><span class="token"> </span><span class="token">&amp;</span><span class="token">#8217;:key&amp;#8217;
</span></span><span class="line"><span class="token">(</span><span class="token" style="color: #6f42c1;">sym</span><span class="token"> </span><span class="token" style="color: #032f62;">:key</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #6f42c1;">ruby-parse</span><span class="token"> </span><span class="token" style="color: #005cc5;">-</span><span class="token" style="color: #005cc5;">e</span><span class="token"> </span><span class="token">&amp;</span><span class="token">#8217;[]&amp;#8217;
</span></span><span class="line"><span class="token">(</span><span class="token" style="color: #6f42c1;">array</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #6f42c1;">ruby-parse</span><span class="token"> </span><span class="token" style="color: #005cc5;">-</span><span class="token" style="color: #005cc5;">e</span><span class="token"> </span><span class="token">&amp;</span><span class="token">#8217;{}&amp;#8217;
</span></span><span class="line"><span class="token">(</span><span class="token" style="color: #005cc5;">hash</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-183"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-181">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-182'
	>
	The basic constructs are pretty straightforward. We get a readable description of the code, which tells us that 1 is an <strong>integer</strong> with value 1, while “1” is a <strong>string</strong> with value “1”. We can see that this continues to be the case in more complex expressions:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-185"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-shellscript github-light" data-language="shellscript" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #6f42c1;">ruby-parse</span><span class="token"> </span><span class="token" style="color: #005cc5;">-</span><span class="token" style="color: #005cc5;">e</span><span class="token"> </span><span class="token">&amp;</span><span class="token">#8217;[1, 2, 3]&amp;#8217;
</span></span><span class="line"><span class="token">(</span><span class="token" style="color: #6f42c1;">array</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token">(</span><span class="token" style="color: #6f42c1;">int</span><span class="token"> </span><span class="token" style="color: #005cc5;">1</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token">(</span><span class="token" style="color: #6f42c1;">int</span><span class="token"> </span><span class="token" style="color: #005cc5;">2</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token">(</span><span class="token" style="color: #6f42c1;">int</span><span class="token"> </span><span class="token" style="color: #005cc5;">3</span><span class="token">)</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #6f42c1;">ruby-parse</span><span class="token"> </span><span class="token" style="color: #005cc5;">-</span><span class="token" style="color: #005cc5;">e</span><span class="token"> </span><span class="token">&amp;</span><span class="token">#8217;{username: “john”, password: “doe”}&amp;#8217;
</span></span><span class="line"><span class="token">(</span><span class="token" style="color: #005cc5;">hash</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token">(</span><span class="token" style="color: #6f42c1;">pair</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">(</span><span class="token" style="color: #6f42c1;">sym</span><span class="token"> </span><span class="token" style="color: #032f62;">:username</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">(</span><span class="token" style="color: #6f42c1;">str</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">john</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token">(</span><span class="token" style="color: #6f42c1;">pair</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">(</span><span class="token" style="color: #6f42c1;">sym</span><span class="token"> </span><span class="token" style="color: #032f62;">:password</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">(</span><span class="token" style="color: #6f42c1;">str</span><span class="token"> </span><span class="token" style="color: #032f62;">&quot;</span><span class="token" style="color: #032f62;">doe</span><span class="token" style="color: #032f62;">&quot;</span><span class="token">)</span><span class="token">)</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-188"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-186">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-187'
	>
	If you haven’t grasped what’s going on, it really helps reading the Ruby code out loud. Take a look at the last example and try reading every bit of Ruby code in the most descriptive way possible. I said it the first time like this:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-193"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="blockquote block-blockquote__blockquote" data-id="es-189">
	
	<div class="blockquote__content">
		<i
	class="icon blockquote__icon icon--size-16 icon--scale-100"
	 aria-hidden='true' data-name='blockquote-24' data-id='es-190'>
	<svg fill='none' height='24' viewBox='0 0 24 24' width='24' xmlns='http://www.w3.org/2000/svg'><path clip-rule='evenodd' d='m12 24c6.6274 0 12-5.3726 12-12 0-2.79685-.9568-5.37021-2.561-7.41062-.581.22951-1.0832.60583-1.5069 1.12898-.5132.60844-.7698 1.41969-.7698 2.43375v.07605h2.5789v5.59004h-5.6197v-5.01962c0-1.11547.154-2.06616.4619-2.85205.3336-.81125.757-1.48307 1.2702-2.01545.528-.52161 1.1175-.92155 1.7687-1.1998-2.0728-1.70651-4.7279-2.73128-7.6223-2.73128-6.62742 0-12 5.37258-12 12 0 6.6274 5.37258 12 12 12zm-3.53811-18.05347c-.30793.78589-.46189 1.73658-.46189 2.85205v5.01962h5.6197v-5.59004h-2.5789v-.07605c0-1.01406.2566-1.82531.7698-2.43375.5389-.63379 1.1804-1.05209 1.9245-1.2549v-2.28164c-.7441.07605-1.4626.25351-2.1555.53238-.6928.27887-1.3086.68449-1.84752 1.21688-.51321.53238-.9366 1.2042-1.27019 2.01545z' fill='currentColor' fill-rule='evenodd'/></svg></i><p	class='typography typography--size-36-text js-typography blockquote__quote'
	data-id='es-191'
	>
	I have a hash that contains 2 elements, where the first element key is :username and value is “john” and the second element key is :password and value is “doe”.</p>
		<div class="blockquote__caption-wrap">
					</div>
	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-196"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-194">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-195'
	>
	This is not explicit enough, because I didn’t specify the primitive type of the key (symbol) and value (string) of the elements.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-199"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-197">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-198'
	>
	So, let’s investigate the AST of our example:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-201"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-shellscript github-light" data-language="shellscript" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #6f42c1;">ruby-parse</span><span class="token"> </span><span class="token" style="color: #005cc5;">-</span><span class="token" style="color: #005cc5;">e</span><span class="token"> </span><span class="token">&amp;</span><span class="token">#8217;attribute :confirmed_at, :datetime, default: Time.zone.now&amp;#8217;
</span></span><span class="line"><span class="token">(</span><span class="token" style="color: #6f42c1;">send</span><span class="token"> </span><span class="token" style="color: #032f62;">nil</span><span class="token"> </span><span class="token" style="color: #032f62;">:attribute</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token">(</span><span class="token" style="color: #6f42c1;">sym</span><span class="token"> </span><span class="token" style="color: #032f62;">:confirmed_at</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token">(</span><span class="token" style="color: #6f42c1;">sym</span><span class="token"> </span><span class="token" style="color: #032f62;">:datetime</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token">(</span><span class="token" style="color: #005cc5;">hash</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">(</span><span class="token" style="color: #6f42c1;">pair</span><span class="token">
</span></span><span class="line"><span class="token">      </span><span class="token">(</span><span class="token" style="color: #6f42c1;">sym</span><span class="token"> </span><span class="token" style="color: #032f62;">:default</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">      </span><span class="token">(</span><span class="token" style="color: #6f42c1;">send</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token">(</span><span class="token" style="color: #6f42c1;">send</span><span class="token">
</span></span><span class="line"><span class="token">          </span><span class="token">(</span><span class="token" style="color: #6f42c1;">const</span><span class="token"> </span><span class="token" style="color: #032f62;">nil</span><span class="token"> </span><span class="token" style="color: #032f62;">:Time</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #6f42c1;">:zone</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #6f42c1;">:now</span><span class="token">)</span><span class="token">)</span><span class="token">)</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-204"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-202">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-203'
	>
	Looks familiar, doesn’t it? It’s a combination of all the nodes we’ve parsed in the previous examples. Any class that inherits <strong>ApplicationRecord</strong> or includes the <strong>AttributesAPI</strong> module can receive the <em>attribute</em> message that accepts 3 arguments:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-207"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-205">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-206'
	>
	<li><em>symbol</em> confirmed_at</li><li><em>symbol</em> datetime</li><li>keyword argument <em>:default</em> with any value (in our case <em>Time.zone.now</em>)</li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-210"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-208">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-209'
	>
	The AST concept gives us the ability to convert source code into data structures. Now we just need another tool that will traverse the tree and find specific nodes in Ruby using pattern matching, or maybe regular expressions?</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-213"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-211">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-212'
	>
	Node pattern</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-216"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-214">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-215'
	>
	Fortunately for us, this problem has also been solved with the <a href="https://github.com/rubocop-hq/rubocop-ast/blob/master/docs/modules/ROOT/pages/node_pattern.adoc">Node pattern</a>. It is a DSL for finding specific nodes in the AST using simple strings.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-219"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-217">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-218'
	>
	This is the last step before diving into the implementation of a custom cop &#8211; finding the right string that will match against a specific AST. Here are some examples of the Ruby code, AST, and the pattern.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-222"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-220"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-221">
	<picture class="image__picture block-media__image-picture">
								
			<source
				srcset=https://infinum.com/uploads/2020/12/code-quality-rubocop-3-1400x829.webp				media='(max-width: 699px)'
				type=image/webp								height="829"
												width="1400"
				 />
												<img
					src="https://infinum.com/uploads/2020/12/code-quality-rubocop-3.webp"
					class="image__img block-media__image-img"
					alt=""
										height="860"
															width="1452"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-225"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-223">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-224'
	>
	The only real difference between the AST and the pattern is <strong>nil?</strong>, which is a <a href="https://github.com/rubocop-hq/rubocop-ast/blob/master/docs/modules/ROOT/pages/node_pattern.adoc#user-content-nil-or-nil">special case</a> predicate that matches against nil objects. Bear in mind that the goal is to match <strong>arbitrary</strong> code to these patterns, not just our specific examples in the table. We need to take great care of warning of invalid cases while keeping the valid usages unaffected:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-227"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-ruby github-light" data-language="ruby" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">attribute </span><span class="token" style="color: #005cc5;">:</span><span class="token" style="color: #005cc5;">role</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #005cc5;">:</span><span class="token" style="color: #005cc5;">string</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #005cc5;">default</span><span class="token" style="color: #005cc5;">:</span><span class="token"> </span><span class="token" style="color: #005cc5;">:</span><span class="token" style="color: #005cc5;">user</span><span class="token">
</span></span><span class="line"><span class="token">attribute </span><span class="token" style="color: #005cc5;">:</span><span class="token" style="color: #005cc5;">role</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #005cc5;">default</span><span class="token" style="color: #005cc5;">:</span><span class="token"> </span><span class="token" style="color: #005cc5;">:</span><span class="token" style="color: #005cc5;">user</span><span class="token">
</span></span><span class="line"><span class="token">attribute </span><span class="token" style="color: #005cc5;">:</span><span class="token" style="color: #005cc5;">active</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #005cc5;">:</span><span class="token" style="color: #005cc5;">boolean</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #005cc5;">default</span><span class="token" style="color: #005cc5;">:</span><span class="token"> </span><span class="token" style="color: #005cc5;">true</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-230"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-228">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-229'
	>
	Sandi Metz gave an <a href="https://youtu.be/29MAL8pJImQ">excellent talk</a> on RailsConf in 2015, where she stated:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-235"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="blockquote block-blockquote__blockquote" data-id="es-231">
	
	<div class="blockquote__content">
		<i
	class="icon blockquote__icon icon--size-16 icon--scale-100"
	 aria-hidden='true' data-name='blockquote-24' data-id='es-232'>
	<svg fill='none' height='24' viewBox='0 0 24 24' width='24' xmlns='http://www.w3.org/2000/svg'><path clip-rule='evenodd' d='m12 24c6.6274 0 12-5.3726 12-12 0-2.79685-.9568-5.37021-2.561-7.41062-.581.22951-1.0832.60583-1.5069 1.12898-.5132.60844-.7698 1.41969-.7698 2.43375v.07605h2.5789v5.59004h-5.6197v-5.01962c0-1.11547.154-2.06616.4619-2.85205.3336-.81125.757-1.48307 1.2702-2.01545.528-.52161 1.1175-.92155 1.7687-1.1998-2.0728-1.70651-4.7279-2.73128-7.6223-2.73128-6.62742 0-12 5.37258-12 12 0 6.6274 5.37258 12 12 12zm-3.53811-18.05347c-.30793.78589-.46189 1.73658-.46189 2.85205v5.01962h5.6197v-5.59004h-2.5789v-.07605c0-1.01406.2566-1.82531.7698-2.43375.5389-.63379 1.1804-1.05209 1.9245-1.2549v-2.28164c-.7441.07605-1.4626.25351-2.1555.53238-.6928.27887-1.3086.68449-1.84752 1.21688-.51321.53238-.9366 1.2042-1.27019 2.01545z' fill='currentColor' fill-rule='evenodd'/></svg></i><p	class='typography typography--size-36-text js-typography blockquote__quote'
	data-id='es-233'
	>
	You can reveal how things are different, by making them more alike.</p>
		<div class="blockquote__caption-wrap">
					</div>
	</div>
</div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-238"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-236">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-237'
	>
	By putting this quote to use, we can spot the static nodes in an infinite range of code possibilities and reveal the pattern:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-240"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-ruby github-light" data-language="ruby" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">attribute </span><span class="token" style="color: #005cc5;">:</span><span class="token" style="color: #005cc5;">any_name</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #005cc5;">:</span><span class="token" style="color: #005cc5;">optional_argument</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #005cc5;">default</span><span class="token" style="color: #005cc5;">:</span><span class="token"> any_construct
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-243"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-241">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-242'
	>
	<li><em>attribute</em> &#8211; the class method that never changes, so we keep this as “attribute” in the pattern</li><li><em>any_name</em> &#8211; doesn’t really concern us, as long as it is there because the API requires it as a method parameter. This fits the bill nicely for the _ matcher. It will fit <a href="https://github.com/rubocop-hq/rubocop-ast/blob/master/docs/modules/ROOT/pages/node_pattern.adoc#_-for-any-single-node">any single node</a>.</li><li><em>optional_argument</em> &#8211; also doesn’t matter what it is, but it doesn’t have to exist. The &#8220;?&#8221; matcher limits the match to 0 or 1 nodes, and when used in conjunction with &#8220;_&#8221; you effectively create a pattern for any optional construct &#8220;?_&#8221;</li><li><em>default</em> &#8211; the <a href="https://api.rubyonrails.org/classes/ActiveRecord/Attributes/ClassMethods.html#method-i-attribute">Attributes API</a> also receives keyword arguments, but we are only interested in the hash when the first node is a symbol with value “default”. This is covered in the Abstract Syntax Tree chapter by parsing the hash.</li><li><em>any_construct</em> &#8211; this is the target we are interested in. If we can get the type of this node we’ll be able to warn the developer for offending cases like a method call, array or hash, because none of those should be used on the class level, since we’re creating an attribute that will be used on the instance level. The $ matcher <a href="https://github.com/rubocop-hq/rubocop-ast/blob/master/docs/modules/ROOT/pages/node_pattern.adoc#-for-captures">captures the node</a>, making it available for processing.</li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-246"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-244">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-245'
	>
	Let’s use the information and write the pattern that would fit the bill for all cases:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-248"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-shellscript github-light" data-language="shellscript" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">(</span><span class="token" style="color: #6f42c1;">send</span><span class="token"> </span><span class="token" style="color: #032f62;">nil?</span><span class="token"> </span><span class="token" style="color: #032f62;">:attribute</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #6f42c1;">_</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #6f42c1;">?_</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token">(</span><span class="token" style="color: #005cc5;">hash</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">(</span><span class="token" style="color: #6f42c1;">pair</span><span class="token">
</span></span><span class="line"><span class="token">      </span><span class="token">(</span><span class="token" style="color: #6f42c1;">sym</span><span class="token"> </span><span class="token" style="color: #032f62;">:default</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">      </span><span class="token" style="color: #005cc5;">$</span><span class="token" style="color: #005cc5;">_</span><span class="token">)</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-251"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-249">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-250'
	>
	At this point, you should be confident enough to start writing some code.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-254"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-252">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-253'
	>
	Creating the cop</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-257"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-255">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-256'
	>
	We love writing tests, especially when the tests are fast and easy to understand.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-260"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-258">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-259'
	>
	RuboCop provides a beautiful DSL for testing cops but unfortunately a lot of articles found online don’t have the information how to set up cop tests. Don’t worry, we’ve got you covered this time!</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-263"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-261">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-262'
	>
	Here are some tips for setting up RSpec cop tests:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-266"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-264">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-265'
	>
	Make sure RuboCop is in your Gemfile and bundled up.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-269"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-267">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-268'
	>
	Open <em>spec/rails_helper.rb</em> and add:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-271"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-ruby github-light" data-language="ruby" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #d73a49;">require</span><span class="token"> </span><span class="token" style="color: #d73a49;">&amp;</span><span class="token" style="color: #6a737d;">#</span><span class="token" style="color: #6a737d;">8217;rubocop&amp;#8217;</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token" style="color: #d73a49;">require</span><span class="token"> </span><span class="token" style="color: #d73a49;">&amp;</span><span class="token" style="color: #6a737d;">#</span><span class="token" style="color: #6a737d;">8217;rubocop/rspec/support&amp;#8217;</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-274"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-272">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-273'
	>
	Include it globally or specific category of tests (eg. type: :cop):</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-276"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-ruby github-light" data-language="ruby" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #005cc5;">RSpec</span><span class="token">.</span><span class="token" style="color: #6f42c1;">configure</span><span class="token"> </span><span class="token" style="color: #d73a49;">do</span><span class="token"> </span><span class="token" style="color: #d73a49;">|</span><span class="token">config</span><span class="token" style="color: #d73a49;">|</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">  config</span><span class="token">.</span><span class="token" style="color: #d73a49;">include</span><span class="token"> </span><span class="token" style="color: #005cc5;">RuboCop</span><span class="token">::</span><span class="token" style="color: #005cc5;">RSpec</span><span class="token">::</span><span class="token" style="color: #005cc5;">ExpectOffense</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #6a737d;">#</span><span class="token" style="color: #6a737d;"> rest of your rspec configuration</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token" style="color: #d73a49;">end</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-279"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-277">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-278'
	>
	The <strong>ExpectOffense</strong> module provides us with a beautiful way of writing clear and descriptive cop tests. They resemble the actual Ruby code you’re trying to cover:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-281"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-ruby github-light" data-language="ruby" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #6a737d;">#</span><span class="token" style="color: #6a737d;">spec/cop/rails/attribute_default_block_value_spec.rb</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">describe </span><span class="token" style="color: #005cc5;">Cop</span><span class="token">::</span><span class="token" style="color: #005cc5;">Rails</span><span class="token">::</span><span class="token" style="color: #005cc5;">AttributeDefaultBlockValue</span><span class="token"> </span><span class="token" style="color: #d73a49;">do</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #6f42c1;">subject</span><span class="token">(</span><span class="token" style="color: #005cc5;">:</span><span class="token" style="color: #005cc5;">cop</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token"> </span><span class="token">described_class</span><span class="token">.</span><span class="token" style="color: #d73a49;">new</span><span class="token">(</span><span class="token">config</span><span class="token">)</span><span class="token"> </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #6f42c1;">let</span><span class="token">(</span><span class="token" style="color: #005cc5;">:</span><span class="token" style="color: #005cc5;">config</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token"> </span><span class="token" style="color: #005cc5;">RuboCop</span><span class="token">::</span><span class="token" style="color: #005cc5;">Config</span><span class="token">.</span><span class="token" style="color: #d73a49;">new</span><span class="token"> </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #6f42c1;">let</span><span class="token">(</span><span class="token" style="color: #005cc5;">:</span><span class="token" style="color: #005cc5;">message</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token"> </span><span class="token" style="color: #d73a49;">&amp;</span><span class="token" style="color: #6a737d;">#</span><span class="token" style="color: #6a737d;">8217;Pass method in a block to `:default` option.&amp;#8217; }</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">  it </span><span class="token" style="color: #d73a49;">&amp;</span><span class="token" style="color: #6a737d;">#</span><span class="token" style="color: #6a737d;">8217;disallows method called from other objects&amp;#8217; do</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #6f42c1;">expect_offense</span><span class="token">(</span><span class="token" style="color: #032f62;">&lt;&lt;~RUBY</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">      attribute </span><span class="token" style="color: #005cc5;">:</span><span class="token" style="color: #005cc5;">confirmed_at</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #005cc5;">:</span><span class="token" style="color: #005cc5;">datetime</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #005cc5;">default</span><span class="token" style="color: #005cc5;">:</span><span class="token"> </span><span class="token" style="color: #005cc5;">Time</span><span class="token">.</span><span class="token" style="color: #6f42c1;">zone</span><span class="token">.</span><span class="token" style="color: #6f42c1;">now</span><span class="token">
</span></span><span class="line"><span class="token">                                                   </span><span class="token" style="color: #d73a49;">^</span><span class="token" style="color: #d73a49;">^</span><span class="token" style="color: #d73a49;">^</span><span class="token" style="color: #d73a49;">^</span><span class="token" style="color: #d73a49;">^</span><span class="token" style="color: #d73a49;">^</span><span class="token" style="color: #d73a49;">^</span><span class="token" style="color: #d73a49;">^</span><span class="token" style="color: #d73a49;">^</span><span class="token" style="color: #d73a49;">^</span><span class="token" style="color: #d73a49;">^</span><span class="token" style="color: #d73a49;">^</span><span class="token" style="color: #d73a49;">^</span><span class="token"> </span><span class="token">#{</span><span class="token">message</span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #032f62;">    RUBY
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #d73a49;">end</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">end</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-284"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-282">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-283'
	>
	Now we can create the cop:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-286"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-ruby github-light" data-language="ruby" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #6a737d;">#</span><span class="token" style="color: #6a737d;">lib/cop/rails/attribute_default_block_value.rb</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">module</span><span class="token"> </span><span class="token" style="color: #6f42c1;">Cop</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #d73a49;">module</span><span class="token"> </span><span class="token" style="color: #6f42c1;">Rails</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">class</span><span class="token"> </span><span class="token" style="color: #6f42c1;">AttributeDefaultBlockValue</span><span class="token"> </span><span class="token" style="color: #d73a49;">&lt;</span><span class="token"> </span><span class="token">::</span><span class="token" style="color: #005cc5;">RuboCop</span><span class="token">::</span><span class="token" style="color: #005cc5;">Cop</span><span class="token">::</span><span class="token" style="color: #005cc5;">Cop</span><span class="token">
</span></span><span class="line"><span class="token">      </span><span class="token" style="color: #005cc5;">MSG</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #d73a49;">&amp;</span><span class="token" style="color: #6a737d;">#</span><span class="token" style="color: #6a737d;">8217;Pass method in a block to `:default` option.&amp;#8217;</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token">      </span><span class="token" style="color: #005cc5;">TYPE_OFFENDERS</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #005cc5;">%i[</span><span class="token" style="color: #005cc5;">send array hash</span><span class="token" style="color: #005cc5;">]</span><span class="token">.</span><span class="token" style="color: #6f42c1;">freeze</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">      def_node_matcher </span><span class="token" style="color: #005cc5;">:</span><span class="token" style="color: #005cc5;">default_attribute</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #032f62;">&lt;&lt;~PATTERN</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #032f62;">        (send nil? :attribute _ ?_ (hash &lt;$#attribute ...&gt;))
</span></span><span class="line"><span class="token" style="color: #032f62;">      PATTERN</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">      def_node_matcher </span><span class="token" style="color: #005cc5;">:</span><span class="token" style="color: #005cc5;">attribute</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #d73a49;">&amp;</span><span class="token" style="color: #6a737d;">#</span><span class="token" style="color: #6a737d;">8217;(pair (sym :default) $_)&amp;#8217;</span><span class="token" style="color: #6a737d;">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">      </span><span class="token" style="color: #d73a49;">def</span><span class="token"> </span><span class="token" style="color: #6f42c1;">on_send</span><span class="token">(</span><span class="token">node</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #6f42c1;">default_attribute</span><span class="token">(</span><span class="token">node</span><span class="token">)</span><span class="token"> </span><span class="token" style="color: #d73a49;">do</span><span class="token"> </span><span class="token" style="color: #d73a49;">|</span><span class="token">attribute</span><span class="token" style="color: #d73a49;">|</span><span class="token">
</span></span><span class="line"><span class="token">          </span><span class="token" style="color: #e36209;">value</span><span class="token"> </span><span class="token" style="color: #d73a49;">=</span><span class="token"> attribute</span><span class="token">.</span><span class="token" style="color: #6f42c1;">children</span><span class="token">.</span><span class="token" style="color: #6f42c1;">last</span><span class="token">
</span></span><span class="line"><span class="token">          </span><span class="token" style="color: #d73a49;">return</span><span class="token"> </span><span class="token" style="color: #d73a49;">unless</span><span class="token"> </span><span class="token" style="color: #005cc5;">TYPE_OFFENDERS</span><span class="token">.</span><span class="token" style="color: #6f42c1;">any?</span><span class="token"> </span><span class="token">{</span><span class="token"> </span><span class="token" style="color: #d73a49;">|</span><span class="token">type</span><span class="token" style="color: #d73a49;">|</span><span class="token"> value</span><span class="token">.</span><span class="token" style="color: #6f42c1;">type</span><span class="token"> </span><span class="token" style="color: #d73a49;">==</span><span class="token"> type </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">          </span><span class="token" style="color: #6f42c1;">add_offense</span><span class="token">(</span><span class="token">node</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #005cc5;">location</span><span class="token" style="color: #005cc5;">:</span><span class="token"> value</span><span class="token">)</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #d73a49;">end</span><span class="token">
</span></span><span class="line"><span class="token">      </span><span class="token" style="color: #d73a49;">end</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">end</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token" style="color: #d73a49;">end</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #d73a49;">end</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-289"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-287">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-288'
	>
	<em>RuboCop::Cop::Cop</em> provides a bunch of stuff that’s used in all class instance cops.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-292"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-290">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-291'
	>
	The <strong>def_node_matcher</strong> method is used for matching nodes. It requires the name of the matcher and the matching pattern. In the example above I used matcher chaining, but you can just as easily use one matcher with the AST that was defined at the end of the previous chapter:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-294"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-ruby github-light" data-language="ruby" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">def_node_matcher </span><span class="token" style="color: #005cc5;">:</span><span class="token" style="color: #005cc5;">default_attribute</span><span class="token">,</span><span class="token"> </span><span class="token" style="color: #032f62;">&lt;&lt;~PATTERN</span><span class="token">
</span></span><span class="line"><span class="token" style="color: #032f62;">  (send nil? :attribute
</span></span><span class="line"><span class="token" style="color: #032f62;">    _
</span></span><span class="line"><span class="token" style="color: #032f62;">    ?_
</span></span><span class="line"><span class="token" style="color: #032f62;">    (hash
</span></span><span class="line"><span class="token" style="color: #032f62;">      (pair
</span></span><span class="line"><span class="token" style="color: #032f62;">        (sym :default)
</span></span><span class="line"><span class="token" style="color: #032f62;">        $_))
</span></span><span class="line"><span class="token" style="color: #032f62;">PATTERN</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-297"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-295">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-296'
	>
	Callback methods (on_send, on_block, on_class etc…) check whether a node is matched against a pattern. You know what callback to use from the first node AST, which in our case is <strong>send</strong>. We used def on_send(node).</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-300"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-298">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-299'
	>
	Inside of the callback methods you usually start off with the matcher name defined in def_node_matcher in order to get the offending construct. When calling default_attribute(node), you get an instance of a type of <strong>RuboCop::AST::Node</strong> that knows its type and node children, alongside other things.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-303"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-301">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-302'
	>
	The <strong>add_offense</strong> method provides an easy way of adding a warning message, defining the error positioning (^^^) and the severity of the error:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-306"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-304">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-305'
	>
	<li>refactor</li><li>convention</li><li>warning</li><li>error</li><li>fatal</li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-309"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-307">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-308'
	>
	I advise you to look at the <a href="https://github.com/rubocop-hq/rubocop">RuboCop source code</a>, because it’s really nicely documented and there’s a lot of examples for learning. The rest is just…Ruby.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-312"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-310">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-311'
	>
	Lastly, include your new cop in <em>.rubocop.yml</em>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-314"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-yaml github-light" data-language="yaml" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #22863a;">r</span><span class="token" style="color: #22863a;">equire</span><span class="token">:</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token">-</span><span class="token"> </span><span class="token" style="color: #032f62;">.</span><span class="token" style="color: #032f62;">/lib/cop/rails/attribute_default_block_value</span><span class="token">
</span></span><span class="line"><span class="token">  </span><span class="token">-</span><span class="token"> </span><span class="token" style="color: #032f62;">r</span><span class="token" style="color: #032f62;">ubocop-infinum</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-317"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-315">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-316'
	>
	Upon reopening or changing a file, you should see the new cop in action.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-320"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-318"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-319">
	<picture class="image__picture block-media__image-picture">
								
			<source
				srcset=https://infinum.com/uploads/2020/12/code-quality-rubocop-4-1400x276.webp				media='(max-width: 699px)'
				type=image/webp								height="276"
												width="1400"
				 />
												<img
					src="https://infinum.com/uploads/2020/12/code-quality-rubocop-4.webp"
					class="image__img block-media__image-img"
					alt=""
										height="306"
															width="1550"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-323"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-321">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-322'
	>
	Want cleaner pull requests?</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-326"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-324">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-325'
	>
	Code reviews are important and the discussions should focus on strategies used to solve the domain-specific problem, finding edge cases, and pointing out possible design or test improvements. They should have a minimum number of comments related to project conventions, as well as company code conventions, typos, or syntax errors.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-329"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-327">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-328'
	>
	Having a quick feedback loop in your IDE enables all of that, while being much more effective time-wise than PR reviews.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-332"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-330">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-331'
	>
	Another benefit is the feeling of accomplishment when your custom cop gets recognized as useful and gets promoted from a project-specific cop to a company-specific one. Maybe it will even get <a href="https://github.com/rubocop-hq/rubocop-rails/pull/339">merged</a> with the other cops to serve and protect codebases all around the world.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-335"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-333">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-334'
	>
	We use RuboCop at Infinum and have only started down this road, but we see a lot of benefits. Having cleaner pull requests, automated knowledge sharing and being able to engage with open source software makes it a no-brainer.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-338"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-336">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-337'
	>
	The Ruby community is one of the nicest programming-language-related communities out there and we should all actively search for ways to improve it and help other fellow developers write good, clean code.</p></div>	</div>
</div>
</div>		</div>
	</div><p>The post <a href="https://infinum.com/blog/code-quality-rubocop/">Improve Code Quality with RuboCop</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</content:encoded>
			</item>
					<item>
				<image>
					<url>8069https://infinum.com/uploads/2017/02/analyzing-rubygems-stats-v2016-0.webp</url>
				</image>
				<title>Is Ruby Dead? Hell No!  Analyzing RubyGems Stats for 2016</title>
				<link>https://infinum.com/blog/analyzing-rubygems-stats-v2016/</link>
				<pubDate>Tue, 17 Jan 2017 16:25:00 +0000</pubDate>
				<dc:creator>Marko Ćilimković</dc:creator>
				<guid isPermaLink="false">https://infinum.com/the-capsized-eight/analyzing-rubygems-stats-v2016/</guid>
				<description>
					<![CDATA[<p>JavaScript frameworks are growing in number, new languages are developed faster than ever, and people are still talking about the death of Ruby and Rails.</p>
<p>The post <a href="https://infinum.com/blog/analyzing-rubygems-stats-v2016/">Is Ruby Dead? Hell No!  Analyzing RubyGems Stats for 2016</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</description>
				<content:encoded>
					<![CDATA[<div
	class="wrapper"
	data-id="es-532"
	 data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-blog-content js-block-blog-content">
	
<div class="block-blog-content-sidebar" data-id="es-341">
	</div>

<div class="block-blog-content-main">
	
<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-344"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-342">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-343'
	>
	Another year is behind us and many things have changed in the web development world – the number of JavaScript frameworks continues to grow, new programming languages are being developed faster than ever and people are still talking about the death of Ruby and Rails.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-347"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-345">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-346'
	>
	We did a little research on the use of Ruby gems and created some stats for 2016 which prove otherwise.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-350"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-348">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-349'
	>
	Sources</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-353"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-351">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-352'
	>
	At the beginning of last year we used the official <a href="https://rubygems.org/">Rubygems</a> data dumps which consisted of a Postgres database and a Redis store to create an <a href="https://infinum.com/blog/analyzing-rubygems-stats-v2015/">overview of the Ruby ecosystem in 2015</a>. Due to Rubygems <a href="http://blog.rubygems.org/2016/05/19/simplifying-our-stack.html">simplifying their stack</a>, we could no longer access some of the data we collected the previous year because their Redis instances were shut down.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-356"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-354">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-355'
	>
	However, we still used their <a href="https://rubygems.org/pages/data">Postgres database dump</a> for some of the stats. Additionally, we used <a href="http://bestgems.org/">BestGems’</a> API which provided us with a daily insight into the total number of downloads for any gem we were interested in.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-359"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-357">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-358'
	>
	Gem creation continues to fall</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-362"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-360">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-361'
	>
	With only 16.000 gems created this year compared to 26.000 in 2014, one could assume that something is not right. My opinion is twofold. Nowadays, web development is changing rapidly, and requests for web applications are becoming more complicated. This makes our code more complicated, and therefore developers find other ways of producing code, which results in the creation of other frameworks and languages.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-365"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-363">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-364'
	>
	But the language’s stability also plays a big role. We don’t need to create new gems because a version of a gem that does exactly what you need probably exists already.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-368"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-366">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-367'
	>
	Gem releases going down</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-371"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-369">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-370'
	>
	This is strongly correlated to the first trend. Fewer gems created, fewer bugs, fewer version releases.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-374"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-372">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-373'
	>
	Rails downloads are still increasing</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-377"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-375">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-376'
	>
	If we compare the stats with last year’s, there’s an increase of 46% with an obvious spike in July due to the <a href="http://weblog.rubyonrails.org/2016/6/30/Rails-5-0-final/">release of Rails 5.0</a>. Unfortunately, because of Rubygems’ stack simplification we couldn’t get the numbers for each Rails version. But, by using a little math, we calculated that there were around 1.78 million downloads of Rails 5 and around 2 million downloads of Rails 4.2.7. The rest went to prior versions.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-380"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-378">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-379'
	>
	Rails alternatives in 2016</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-383"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-381">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-382'
	>
	Sinatra – used 95% less than Rails</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-386"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-384">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-385'
	>
	<a href="http://www.sinatrarb.com/">Sinatra</a> is being used 95% less than Rails, which is not bad at all considering Rails is the number one go-to framework for Ruby. Comparing the numbers from 2015, we can see an increase of 15%, which translates to 2 million more downloads. Also, the average download count in 2016 was around 1 million, which was the peak in 2015.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-389"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-387">
	<h3	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-388'
	>
	Other frameworks have a much lower download count</h3></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-392"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-390">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-391'
	>
	<a href="http://padrinorb.com/">Padrino</a>, Sinatra’s godfather, had many additions and fixes, including support for Ruby 2.3. Overall, it grew slightly in its total download count but still lacks active users.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-395"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-393">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-394'
	>
	Volt, the Ruby framework in which Ruby code runs on both the server and the client via Opal seems to be stagnating since there were no releases nor commits in 2016.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-398"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-396">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-397'
	>
	Lotus, a tiny web framework with a more object-oriented style than Rails, had to change its name to <a href="http://hanamirb.org/">Hanami</a>, because of IBM’s Lotus Software. Despite having a stable version and a bigger community than in 2015, it still lacks users.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-401"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-399">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-400'
	>
	Database Adapters</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-404"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-402">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-403'
	>
	Interestingly, Postgres usage blew up in 2015 and left MySQL behind, and even though its download count rose even more in 2016, MySQL almost caught up with just around 2 million downloads less during the whole year.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-407"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-405">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-406'
	>
	Mongo’s usage remains consistent, with a slight increase, but it holds 1st place in the NoSQL databases category.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-410"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-408">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-409'
	>
	Application Servers</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-413"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-411">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-412'
	>
	<a href="https://github.com/macournoyer/thin">Thin</a>, <a href="https://github.com/puma/puma">Puma</a> and <a href="https://github.com/defunkt/unicorn">Unicorn</a> are obviously being downloaded more and more with each passing month. Thin is surprisingly still in 1st place, but Puma will probably surpass it, since Heroku listed it as the <a href="https://devcenter.heroku.com/changelog-items/594">recommended web server</a>, and it replaced Rails’ default web server WEBrick with the release of Rails 5.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-416"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-414">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-415'
	>
	<a href="https://www.phusionpassenger.com/">Passenger</a> is stagnating at approximately 100k downloads per month. However, it also comes as a standalone Unix package, so the stats are probably higher.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-419"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-417">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-418'
	>
	Sequel – amazingly amazing</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-422"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-420">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-421'
	>
	Apparently, developers just love writing code without having to resort to custom SQL queries. The awesomely flexible <a href="https://github.com/jeremyevans/sequel">Sequel</a> database access toolkit for Ruby remains stable and is very well supported (0 issues, 0 pull requests) with releases coming on a monthly basis.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-425"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-423">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-424'
	>
	Interestingly, in 2015 they had an 180% increase in usage, which means it was downloaded a bit below 300k times per month. In 2016, it was downloaded 450k times per month on average. Awesome work, <a href="https://github.com/jeremyevans">Jeremy</a>!</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-428"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-426">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-427'
	>
	RSpec – The New King of Testing</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-431"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-429">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-430'
	>
	If I had to single out one thing that was talked about the most in the world of Rubyists in 2016, it’s testing! Testing does save your bacon, and according to stats, we do love our bacon.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-434"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-432">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-433'
	>
	<a href="https://github.com/seattlerb/minitest">Minitest</a> is still a runtime dependency for many gems such as ActiveSupport or Sinatra which makes the download count increase monthly, but <a href="http://rspec.info/">RSpec</a> had more downloads in November and December. This proves that developers choose to install another testing framework and hopefully don’t leave only the scaffolding lines in their testing files.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-437"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-435">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-436'
	>
	We investigated why the sudden rise happened in August, but couldn’t figure out the cause. We assume that a gem that had RSpec as a runtime dependency became very popular at that time.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-440"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-438">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-439'
	>
	Background Workers</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-443"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-441">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-442'
	>
	<a href="http://sidekiq.org/">Sidekiq</a> really is faster than its competition! With the release of 4.0 in late 2015 that removed a lot of dependencies and was completely <a href="http://www.mikeperham.com/2015/10/14/optimizing-sidekiq/">refactored for performance</a>, it’s clearly visible how it impacted Ruby developers, with nearly two times more downloads than in the previous year.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-446"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-444">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-445'
	>
	<a href="https://github.com/resque/resque">Resque</a> and <a href="https://github.com/collectiveidea/delayed_job">Delayed job</a> mostly stayed the same throughout the whole year.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-449"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-447">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-448'
	>
	Authentication aka Devise for Rubyists</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-452"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-450">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-451'
	>
	With <a href="https://github.com/plataformatec/devise">Devise</a> being the de facto Rails authentication solution, no other authentication layer could even compete. I compared its usage in 2015 and 2016, and both results reflect its increasing popularity, counting more than 6.5 million downloads.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-455"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-453">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-454'
	>
	Authorization – CanCanCan VS Pundit</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-458"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-456">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-457'
	>
	In <a href="https://infinum.com/blog/analyzing-rubygems-stats-v2015/">last year’s blog post</a> Damir stated <a href="https://github.com/elabs/pundit">Pundit</a> should be preferred over <a href="https://github.com/CanCanCommunity/cancancan">CanCanCan</a>. With its nice object-oriented minimal authorization, it almost caught up with CanCanCan at the end of the year, showing how Rubyists have good taste when it comes to code structure and architecture.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-461"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-459">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-460'
	>
	Administration Frameworks</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-464"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-462">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-463'
	>
	Rails is a popular web framework for many reasons, one being that it also provides many choices for developers when tailoring the administration interfaces for their web applications. If you have simple model relations and a ‘straight-forward’ blog-like website, it is advisable to use one of the gems that provide you one.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-467"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-465">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-466'
	>
	The two most used UI frameworks, <a href="http://activeadmin.info/">ActiveAdmin</a> and <a href="https://github.com/sferik/rails_admin">RailsAdmin</a>, are reaching their highest usages ever, with more than a 60% increase in downloads in 2016.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-470"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-468">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-469'
	>
	Content Management Systems</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-473"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-471">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-472'
	>
	Discussing Content Management Systems can be quite misleading, since they usually depend on the architecture and business logic of a project. I advise you not to make decisions based on graph stats, but rather test them out for yourself and see what suits your specifications best.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-476"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-474">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-475'
	>
	We crunched the numbers for the most used ones, and there were no great differences when compared to previous years.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-479"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-477">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-478'
	>
	<a href="http://www.refinerycms.com/">RefineryCMS</a> is a well known CMS that is designed for end users to create all of the website content. It is simple to use, flexible when designing and <a href="http://www.refinerycms.com/extensions">extendable</a>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-482"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-480">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-481'
	>
	<a href="https://alchemy-cms.com/about">AlchemyCMS</a> is more developer-oriented because it is more flexible in certain situations. Only the content itself is manipulated by the end user, not the HTML attributes of the page. Everything else is persisted to the database.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-485"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-483">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-484'
	>
	<a href="https://www.locomotivecms.com/">LocomotiveCMS</a> uses <a href="https://www.lewagon.com/">Wagon</a>, a command line tool for creating pages and other content on your local machine. It has a very flexible and nice admin interface, a great community but unfortunately not a lot of users.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-488"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-486">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-487'
	>
	Pagination</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-491"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-489">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-490'
	>
	This comparison surprised me since I’m a Rails developer coming from the <a href="https://www.railstutorial.org/">online school of Michael Hartl</a> that gives an example of pagination using the <a href="https://github.com/mislav/will_paginate">will_paginate gem</a>. However, looking at the usage statistics from previous years, <a href="https://github.com/kaminari/kaminari">kaminari</a> was always in the lead. If you haven’t heard about it, definitely give it a try. It provides a clean, flexible solution with scopes that is also highly configurable.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-494"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-492">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-493'
	>
	File upload Solutions</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-497"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-495">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-496'
	>
	Even though <a href="https://github.com/thoughtbot/paperclip">Paperclip</a> leads with the total number of downloads, <a href="https://github.com/carrierwaveuploader/carrierwave">CarrierWave</a> took over in October with a positive trend continuing in January 2017. CarrierWave is much more flexible and offers many options in its configuration. If you’re interested, check out our <a href="https://infinum.com/blog/best-rails-image-uploader-paperclip-carrierwave-refile/">detailed overview of FileUpload solutions</a>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-500"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-498">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-499'
	>
	Deployment Tools</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-503"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-501">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-502'
	>
	Lastly, as you might expect, <a href="http://capistranorb.com/">Capistrano</a> remains the number 1 deployment tool with over 300.000 downloads monthly. Since it has no close competition, we compared its usage statistics from 2015 and 2016. There was an increase of more than 20% with over 3.5 million downloads.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-506"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-504">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-505'
	>
	Aggregated stats for 2016</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-509"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-507">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-508'
	>
	<li>Rails was downloaded more than 24 million times</li><li>44 gems were released per day</li><li>332 gem versions were released per day</li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-512"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-510">
	<h2	class='typography typography--size-52-default js-typography block-heading__heading'
	data-id='es-511'
	>
	Conclusion</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-515"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-513">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-514'
	>
	PHP, Java and Ruby now have one thing in common: despite obvious usage trends, everybody keeps talking about their deaths.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-518"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-516">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-517'
	>
	We are living in an era when anything slightly popular, if exploited properly, can explode and be in the spotlight for a certain amount of time. This used to be the case with Ruby on Rails. However, after many years the hype is going down.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-521"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-519">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-520'
	>
	All programming languages are good for something, but none are perfect for everything, and Rails still has its place.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-524"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-522">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-523'
	>
	Despite the rise of Ruby on Rails alternatives, developers still appreciate the benefits of a large and stable ecosystem with a mature community and easily choose a turn-key solution like Rails for rapid web development.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-527"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-525">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-526'
	>
	And Rails is keeping up with trends – Rails 5 has a pure API mode now, <a href="https://github.com/rails/rails/pull/26836">Yarn support</a>, <a href="https://github.com/rails/rails/pull/27288">Webpack support</a> and we’re glad it’s going in that direction. These three changes will help us a lot because they make up the outline of how we build web apps at Infinum.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-530"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-528">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-529'
	>
	Read, study, examine, try. Find a language that fits you most and if one doesn’t work, repeat those steps. Rails isn’t going anywhere anytime soon.</p></div>	</div>
</div>
</div>		</div>
	</div><p>The post <a href="https://infinum.com/blog/analyzing-rubygems-stats-v2016/">Is Ruby Dead? Hell No!  Analyzing RubyGems Stats for 2016</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</content:encoded>
			</item>
		
	</channel>
</rss>