<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: R.J. Robinson</title>
    <description>The latest articles on Forem by R.J. Robinson (@rjrobinson).</description>
    <link>https://forem.com/rjrobinson</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F137535%2F2d471b83-b23f-43c6-9d7a-93bb1973f750.jpg</url>
      <title>Forem: R.J. Robinson</title>
      <link>https://forem.com/rjrobinson</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/rjrobinson"/>
    <language>en</language>
    <item>
      <title>[Boost]</title>
      <dc:creator>R.J. Robinson</dc:creator>
      <pubDate>Fri, 18 Jul 2025 16:40:29 +0000</pubDate>
      <link>https://forem.com/rjrobinson/-3904</link>
      <guid>https://forem.com/rjrobinson/-3904</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/rjrobinson/build-llm-agents-in-ruby-with-flownodes-a-langchain-alternative-41ab" class="crayons-story__hidden-navigation-link"&gt;🚀 Build LLM Agents in Ruby with FlowNodes — a LangChain Alternative&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/rjrobinson" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F137535%2F2d471b83-b23f-43c6-9d7a-93bb1973f750.jpg" alt="rjrobinson profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/rjrobinson" class="crayons-story__secondary fw-medium m:hidden"&gt;
              R.J. Robinson
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                R.J. Robinson
                
              
              &lt;div id="story-author-preview-content-2703969" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/rjrobinson" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F137535%2F2d471b83-b23f-43c6-9d7a-93bb1973f750.jpg" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;R.J. Robinson&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/rjrobinson/build-llm-agents-in-ruby-with-flownodes-a-langchain-alternative-41ab" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Jul 18 '25&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/rjrobinson/build-llm-agents-in-ruby-with-flownodes-a-langchain-alternative-41ab" id="article-link-2703969"&gt;
          🚀 Build LLM Agents in Ruby with FlowNodes — a LangChain Alternative
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/webdev"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;webdev&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/ruby"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;ruby&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/rails"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;rails&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/llm"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;llm&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/rjrobinson/build-llm-agents-in-ruby-with-flownodes-a-langchain-alternative-41ab" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;2&lt;span class="hidden s:inline"&gt; reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/rjrobinson/build-llm-agents-in-ruby-with-flownodes-a-langchain-alternative-41ab#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              &lt;span class="hidden s:inline"&gt;Add Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            2 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>webdev</category>
      <category>ruby</category>
      <category>rails</category>
      <category>llm</category>
    </item>
    <item>
      <title>🚀 Build LLM Agents in Ruby with FlowNodes — a LangChain Alternative</title>
      <dc:creator>R.J. Robinson</dc:creator>
      <pubDate>Fri, 18 Jul 2025 16:40:21 +0000</pubDate>
      <link>https://forem.com/rjrobinson/build-llm-agents-in-ruby-with-flownodes-a-langchain-alternative-41ab</link>
      <guid>https://forem.com/rjrobinson/build-llm-agents-in-ruby-with-flownodes-a-langchain-alternative-41ab</guid>
      <description>&lt;p&gt;Finally, Rubyists get a clean way to build LLM workflows without swimming in TypeScript or bloated Python frameworks.&lt;/p&gt;

&lt;p&gt;This was inspired by PocketFlow — a ~100-line Python framework that blew me away with its simplicity.&lt;br&gt;
I loved the graph-based pattern so much, I built FlowNodes to bring that same power to Ruby. Now I use it in my own projects, and it just works.&lt;/p&gt;

&lt;p&gt;⸻&lt;/p&gt;

&lt;p&gt;💡 What is FlowNodes?&lt;/p&gt;

&lt;p&gt;FlowNodes is a minimalist Ruby framework for building LLM-powered applications using a graph-based flow architecture — inspired by PocketFlow, rebuilt for the Rails ecosystem.&lt;/p&gt;

&lt;p&gt;Think of it as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🧠 Agents without chaos&lt;/li&gt;
&lt;li&gt;🧩 Workflows without brittle prompt-chaining&lt;/li&gt;
&lt;li&gt;🪄 RAG pipelines without rolling your own spaghetti logic&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All while staying in Ruby. No extra services. No lang-* wrappers.&lt;br&gt;
You can even integrate it with RubyLLM, which supercharges its capabilities.&lt;/p&gt;

&lt;p&gt;⸻&lt;/p&gt;

&lt;p&gt;🧱 Why I Built This&lt;/p&gt;

&lt;p&gt;I wanted something that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Didn’t require Python glue code&lt;/li&gt;
&lt;li&gt;Didn’t assume I wanted 14 layers of abstraction&lt;/li&gt;
&lt;li&gt;Let me define clear flows: “User input → Tool → Decision → Output”&lt;/li&gt;
&lt;li&gt;Could run inside my existing Rails stack — not in some weird sidecar&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;FlowNodes does exactly that. It’s a Ruby-first approach to orchestrating LLM workflows.&lt;/p&gt;

&lt;p&gt;Fun fact: I once rewrote the core in ~88 lines using metaprogramming… but debugging it was hell. Readability wins.&lt;/p&gt;

&lt;p&gt;⸻&lt;/p&gt;

&lt;p&gt;🧪 How It Works (TL;DR)&lt;/p&gt;

&lt;p&gt;Define your flow with simple Ruby classes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GreetingNode&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;FlowNodes&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Node&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;exec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"Hello, &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;!"&lt;/span&gt;
    &lt;span class="s2"&gt;"greeted"&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FarewellNode&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;FlowNodes&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Node&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;exec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"Goodbye, &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;!"&lt;/span&gt;
    &lt;span class="kp"&gt;nil&lt;/span&gt; &lt;span class="c1"&gt;# End the flow&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;greeting&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;GreetingNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;
&lt;span class="n"&gt;farewell&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;FarewellNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;

&lt;span class="c1"&gt;# Connect nodes: greeting -&amp;gt; farewell&lt;/span&gt;
&lt;span class="n"&gt;greeting&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="ss"&gt;:greeted&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;farewell&lt;/span&gt;

&lt;span class="n"&gt;flow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;FlowNodes&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Flow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;start: &lt;/span&gt;&lt;span class="n"&gt;greeting&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;flow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_params&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;name: &lt;/span&gt;&lt;span class="s2"&gt;"World"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;flow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You’re literally just connecting logic like a graph. It’s simple, explicit, and debuggable.&lt;/p&gt;

&lt;p&gt;⸻&lt;/p&gt;

&lt;p&gt;🧰 Features You’ll Actually Use&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Graph-based node chaining (not magic, just clean)&lt;/li&gt;
&lt;li&gt;Async &amp;amp; parallel batch support&lt;/li&gt;
&lt;li&gt;Built-in retry and fallback logic&lt;/li&gt;
&lt;li&gt;Validated parameters&lt;/li&gt;
&lt;li&gt;Lifecycle hooks (prep, exec, post)&lt;/li&gt;
&lt;li&gt;Thread-safe and production-ready&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The core gem is under 500 lines — you can grok the whole thing in an afternoon.&lt;br&gt;
Performance metrics, observability, and memory stores are coming — but the philosophy stays lean and fast.&lt;/p&gt;

&lt;p&gt;⸻&lt;/p&gt;

&lt;p&gt;⚙️ Real Use Cases&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Toolchain-based LLM agents&lt;/li&gt;
&lt;li&gt;Context-aware email/report generators&lt;/li&gt;
&lt;li&gt;Batch RAG queries across PDFs or embeddings&lt;/li&gt;
&lt;li&gt;Multi-step AI flows inside your Rails apps&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You don’t need LangChain. You don’t need Python. You just need Ruby.&lt;/p&gt;

&lt;p&gt;⸻&lt;/p&gt;

&lt;p&gt;🛠 Ready to Try?&lt;/p&gt;

&lt;p&gt;&lt;code&gt;gem install flow_nodes&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Or add it to your Gemfile:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;gem 'flow_nodes', '~&amp;gt; 0.1.0'&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Tutorial (built with AI):&lt;br&gt;
📚 &lt;a href="https://code2tutorial.com/tutorial/927c15a8-5bba-45d8-a999-6ee873562c5a/index.md" rel="noopener noreferrer"&gt;https://code2tutorial.com/tutorial/927c15a8-5bba-45d8-a999-6ee873562c5a/index.md&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;⸻&lt;/p&gt;

&lt;p&gt;🗺 What’s Next&lt;/p&gt;

&lt;p&gt;Coming soon:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Flow visualizations&lt;/li&gt;
&lt;li&gt;Built-in memory stores&lt;/li&gt;
&lt;li&gt;Native Rails generator support&lt;/li&gt;
&lt;li&gt;Community-driven use case templates&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;⸻&lt;/p&gt;

&lt;p&gt;👋 Feedback Wanted&lt;/p&gt;

&lt;p&gt;If you’re a Ruby dev curious about LLMs but tired of fighting Python wrappers, try FlowNodes.&lt;br&gt;
Let me know how you’d use it — or what’s missing to make it battle-tested.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>ruby</category>
      <category>rails</category>
      <category>llm</category>
    </item>
    <item>
      <title>Testing GraphQL-Ruby Mutations With RSpec</title>
      <dc:creator>R.J. Robinson</dc:creator>
      <pubDate>Fri, 19 Jul 2019 15:09:41 +0000</pubDate>
      <link>https://forem.com/rjrobinson/testing-graphql-ruby-mutations-with-rspec-3ngc</link>
      <guid>https://forem.com/rjrobinson/testing-graphql-ruby-mutations-with-rspec-3ngc</guid>
      <description>&lt;p&gt;xpost from medium - love Dev.to so much, wanted to share here as well. &lt;/p&gt;

&lt;p&gt;To start with, a little OpEd on how much I love working with GraphQL. I started tinkering with it about a year ago, and have since completed a project at work where we did a rewrite, the results have been amazing. Pros and cons aside however, I needed a way to test.&lt;br&gt;
This might not be the best solution for you, but this is what had worked on my team, and for our use case. &lt;/p&gt;

&lt;p&gt;The tests needed to cover a few aspects. Did the user have access? We use our own Pundit hack. Were the proper arguments sent? And did the response come back as expected? This sounds like a basic controller test, so from there I treated it as such.&lt;/p&gt;

&lt;p&gt;Usually, in an RSpec controller test, we have a #get or a #post method that allows us to interact with that endpoint, and I wanted to continue with that pattern. These usually return a #response object with everything we would want to test.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;GraphQL::TestHelpers&lt;/span&gt;

  &lt;span class="nb"&gt;attr_accessor&lt;/span&gt; &lt;span class="ss"&gt;:gql_response&lt;/span&gt;

  &lt;span class="c1"&gt;# The returned results of a GraphQL query&lt;/span&gt;
  &lt;span class="c1"&gt;# @return [data] this is the bulk of the return to test.&lt;/span&gt;
  &lt;span class="c1"&gt;# @return [error] any time a query, mutation, subscription throws and error&lt;/span&gt;
  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GQLResponse&lt;/span&gt;
    &lt;span class="nb"&gt;attr_reader&lt;/span&gt; &lt;span class="ss"&gt;:data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:errors&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="vi"&gt;@data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'data'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="kp"&gt;nil&lt;/span&gt;
      &lt;span class="vi"&gt;@errors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'errors'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="kp"&gt;nil&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="c1"&gt;# basic query to interact with the GraphQL API.&lt;/span&gt;
  &lt;span class="c1"&gt;# @param [query] required The query string that would be passed to the schema.&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;variables: &lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="ss"&gt;context: &lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt;

    &lt;span class="n"&gt;converted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;variables&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;deep_transform_keys!&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;camelize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:lower&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

    &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;MyRailsAppSchema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;variables: &lt;/span&gt;&lt;span class="n"&gt;converted&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;context: &lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;operation_name: &lt;/span&gt;&lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@gql_response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;GQLResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_h&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="kp"&gt;alias_method&lt;/span&gt; &lt;span class="ss"&gt;:mutation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:query&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once I defined the #query and #mutation methods, passing in the arguments were easy.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="k"&gt;mutation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;createBook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$bookInput&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BookInputType&lt;/span&gt;&lt;span class="p"&gt;!){&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;createBook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bookInput&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$bookInput&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;book&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;author&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;pages&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;#Arguments== &lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;bookInputType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="n"&gt;Testing&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GraphQL&lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Ruby&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Mutations&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;With&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RSpec&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;author&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="n"&gt;me&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
    &lt;/span&gt;&lt;span class="n"&gt;pages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;1&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Say we have a simple book application, and we want to create a new book. &lt;br&gt;
Below are the tests, and while this seems very basic, I hope it's clear enough to understand the ideas behind it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'rails_helper'&lt;/span&gt;
&lt;span class="nb"&gt;require_relative&lt;/span&gt; &lt;span class="s1"&gt;'../test_helpers'&lt;/span&gt;
&lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;GraphQL&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;TestHelpers&lt;/span&gt;

&lt;span class="n"&gt;describe&lt;/span&gt; &lt;span class="s1"&gt;'CreateBook'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;type: :mutation&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;describe&lt;/span&gt; &lt;span class="s1"&gt;'Creating a Book'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;

    &lt;span class="n"&gt;let&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;build_stubbed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:user&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
    &lt;span class="n"&gt;let&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:mutation_type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"createBook"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;let&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:mutation_string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;-&lt;/span&gt; &lt;span class="no"&gt;GQL&lt;/span&gt;
      &lt;span class="n"&gt;mutation&lt;/span&gt; &lt;span class="n"&gt;createBook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;$bookInput&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;BookInputType&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
       &lt;span class="n"&gt;createBook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;bookInput: &lt;/span&gt;&lt;span class="vg"&gt;$bookInput&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="n"&gt;book&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;title&lt;/span&gt;
            &lt;span class="n"&gt;author&lt;/span&gt;
            &lt;span class="n"&gt;pages&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="no"&gt;GQL&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="s1"&gt;'when a user has all the required permissions and parameters'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;

      &lt;span class="n"&gt;before&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="n"&gt;mutation&lt;/span&gt; &lt;span class="n"&gt;mutation_string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                 &lt;span class="ss"&gt;variables: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="ss"&gt;bookInputType: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
                      &lt;span class="ss"&gt;title: &lt;/span&gt;&lt;span class="s2"&gt;"Testing GraphQL-Ruby Mutations With RSpec"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                      &lt;span class="ss"&gt;author: &lt;/span&gt;&lt;span class="s2"&gt;"me"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                      &lt;span class="ss"&gt;pages: &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt;
                  &lt;span class="p"&gt;}&lt;/span&gt;
                 &lt;span class="p"&gt;},&lt;/span&gt;
                 &lt;span class="ss"&gt;context: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;current_user: &lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;

      &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s1"&gt;'should return no errors'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;gql_response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;be_nil&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;

      &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s1"&gt;'should return the book object'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;gql_response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;mutation_type&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s2"&gt;"book"&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="kp"&gt;include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"title"&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"Testing GraphQL-Ruby Mutations With RSpec"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="s1"&gt;'when a user has not passed required parameters parameters'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;

      &lt;span class="n"&gt;before&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="n"&gt;mutation&lt;/span&gt; &lt;span class="n"&gt;mutation_string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                 &lt;span class="ss"&gt;variables: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="ss"&gt;bookInputType: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
                      &lt;span class="ss"&gt;title: &lt;/span&gt;&lt;span class="s2"&gt;"Testing GraphQL-Ruby Mutations With RSpec"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt;
                  &lt;span class="p"&gt;}&lt;/span&gt;
                 &lt;span class="p"&gt;},&lt;/span&gt;
                 &lt;span class="ss"&gt;context: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;current_user: &lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;

      &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s1"&gt;'should return errors'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;gql_response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;be_truthy&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why did I decide to do it this way? A few reasons. One, I wanted to treat the mutation like any other post request. Data goes in, data comes out. I see a lot of tests trying to do some crazy things just to hit the resolver inside their mutation. I don't really think that's needed. Using the existing interface with the GraphQL Schema should test what you need to. Hope this helps, and I how you provide some feedback. I would love to see how everyone else tests. &lt;/p&gt;

&lt;p&gt;I can be found on twitter. :) &lt;a class="mentioned-user" href="https://dev.to/rjrobinson"&gt;@rjrobinson&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
      <category>graphql</category>
      <category>testing</category>
    </item>
    <item>
      <title>How Intermittent Fasting Improved My Productivity and Other Helpful Tips</title>
      <dc:creator>R.J. Robinson</dc:creator>
      <pubDate>Tue, 28 May 2019 20:07:26 +0000</pubDate>
      <link>https://forem.com/rjrobinson/how-intermittent-fasting-improved-my-productivity-and-other-helpful-tips-ne7</link>
      <guid>https://forem.com/rjrobinson/how-intermittent-fasting-improved-my-productivity-and-other-helpful-tips-ne7</guid>
      <description>&lt;p&gt;I became a developer a few years ago. I would say around 2014/15 is when I really went for it and signed up for a coding boot camp. I was in pretty good shape. I would work out frequently, and I could easily squat 225, and run a few miles without stopping. My clothes fit fine, and I didn't feel bad about taking off my shirt. Then of course... I started sit/standing in front of a computer for 8-10 hours a day. Fast forward past the long days of being a junior developer, and way past my divorce, and I had gained almost 45 pounds ( and not the good gain ) while almost doubling my body fat percentage. &lt;/p&gt;

&lt;p&gt;I was depressed. It was not a fun time in my life. Then the depression started to affect my work, and it was a wake-up call. I had already gone through a lot and I couldn't lose my job on top of it. Luckily for me, I caught that issue early. So, I did what any normal warm-blooded American would do and I started new diets. Several of them. Keto, Atkins, meal prepping. But... it was the cheating on my diet that affected me. Diets were not working. But due to the long term meal prepping ( almost 18 months ), I knew how to measure calories quickly; That was the real trick. &lt;/p&gt;

&lt;p&gt;I have been a productivity fiend for a few months. I didn't want to get bogged down with being unproductive. That was only adding to my depression. I felt good when I accomplished tasks. It was like a little dopamine was released, so I wanted to be able to maximize that feeling, so productivity became the goal. How can I do more work, with less time? &lt;/p&gt;

&lt;p&gt;It all came down to thinking about what had to be done. I read a book called Get $hiT Done (GTS), and the main point of that process was to write things down so that you didn't have to think about them all the time. I didn't realize how much I just forgot to do things. Writing things down on paper ( or iPad in my case) got me programmed to doing so, and then I could just cross something off the list. Boom. Dopamine! All the feels. &lt;/p&gt;

&lt;p&gt;So how could I apply this to my diet? Well, as I mentioned earlier, I had been meal prepping to control how many calories I should take in. The what was answered. What never dawned on me was the when. I had heard about IF (Intermittent Fasting) from some friends, and I thought... that's 2 fewer things to think about for the day. I'm sold. IF, for the everyday reader, is basically a feeding window. You pick a block of time where you can eat, and then you fast for the remainder of the day. Say for instance that you fast between sundown and sunrise, that is called a 13hour fast. One you should start with. The health benefits of IF are seen throughout all of history which is why I suppose that a lot of religions participate in it. &lt;/p&gt;

&lt;p&gt;Over the past few months, I have migrated to an 18 hour fast. I only eat between 1 pm and 7 pm, sleep for 8hours, have black coffee in the morning, and I lost almost 22 pounds the first month. I slept better. I was clearer in my mind. I was grumpy AF around 12. But I got more work done. I got more everything done. Because of meal prep, and IF I had time to go to the gym more. Work on side projects. Long walks with my dog.&lt;/p&gt;

&lt;p&gt;As developers, we think about a lot of things. Another fun thing that we do is automate it. Automate your calorie intake. Stop fighting with people which food truck you should go to. IF helped me. hope it helps you. &lt;/p&gt;

</description>
      <category>diet</category>
      <category>productivity</category>
      <category>fitness</category>
    </item>
  </channel>
</rss>
