10. Ruby Beyond the Basics ll

Overview

By the end of this chapter, you will be able to open classes to add/modify methods; implement monkey patching; use methods such as method_missing and define_method to dynamically create methods at runtime; generate HTTP requests using the built-in Ruby HTTP client net/http; create GET and POST requests using Ruby and create your own gems to share your reusable code.

Introduction

In the previous chapter, we learned about a number of advanced topics, including blocks, procs, and lambdas, which we will use in this chapter when we dive deep into the world of metaprogramming. We will also learn when we should not apply metaprogramming concepts by not always crossing the line into monkey patching (which is changing the behavior of classes and ultimately making the code confusing and unmaintainable).

In the second part of this chapter, we will learn a key programming skill that is required in order to create any real-world application that is communicating with external APIs: how to make GET data from a backend server and how to submit data to said server.

The final part of this chapter will help you share and distribute your Ruby code with others. So far, you have learned how to use Ruby gems, but, by the end of this chapter, you will be able to create your own RubyGem package and share it with the world.

Metaprogramming – A Deep Dive

We introduced metaprogramming in the previous chapter and defined it as code that generates code. Ruby has numerous powerful methods that make it possible to allow code that writes code. Furthermore, metaprogramming is most often used to create flexible interfaces. This is especially useful when you create Ruby gems that are pluggable Ruby libraries in other Ruby programs. Metaprogramming is also used in creating Ruby-based frameworks, such as Sinatra, Ruby on Rails, or when you create your own framework. Ruby on Rails, the most popular Ruby framework, is loaded with metaprogramming magic.

In the previous chapter, we stated that metaprogramming makes use of multiple elements available within the Ruby language. We discussed three such elements: blocks, procs, and lambdas. In this section, we will take a practical approach in order to understand metaprogramming and discuss topics such as opening classes in Ruby, monkey patching, and some in-built Ruby methods that allow you to create methods dynamically at runtime.

Opening Classes

Opening classes is a way in Ruby that allows us to make changes to methods that reside inside the class or to add new methods. This is also called functional reloading or monkey patching. In Ruby, a class is never closed; you can always add new methods to an existing class. This applies not just to classes you create, but in-built standard Ruby classes too. Besides adding new methods to further enhance the power of a class, you can also override the in-built methods. This is called monkey patching.

You should be careful with open classes, especially when you are modifying or overriding an in-built method. Since that alteration will be valid throughout your application, you must be careful and meticulous while writing such code. It is advisable to alias the method or write a new method altogether. We will learn more about this with the help of examples in the next section.

Now, let's understand the syntax to open a class by means of a simple example. In the following example, we create a Ruby file, open_class_integer.rb, and then create an integer class that will add the number 8 to the integer that is provided:

class Integer

  def add_eight

    self + 8

  end

end

puts 9.add_eight

Run this Ruby file from the Terminal. The output will be as follows:

$ ruby open_class_integer.rb

> 17

This is a very simple example where we have added a new method, add_eight, to Ruby's Integer class. So, in our Ruby program, if we call this method on an integer, it will add 8 to it just like in the preceding example, where we have called the method on an integer object with the value of 9, and the result is 17.

Exercise 10.01: Opening the Ruby String Class to Add a New Method to it

The String class is an in-built Ruby class. In this exercise, we will open that class and add a new method, add_prefix, to it. This method will prefix whatever string is passed to it. The following steps will help you to complete the exercise:

  1. Open the string class and add an additional method, add_prefix, to it. Inside the add_prefix method, we have a default string value added:

    class String

      def add_prefix

        "My favorite book is " + self

      end

    end

  2. Now, call the method on a string outside the class and you will see the prefix getting attached to the string value:

    puts "Ruby Fundamentals".add_prefix

  3. Open the file in the Terminal and check the output:
Figure 10.1: Output for the add.prefix method

Figure 10.1: Output for the add.prefix method

Thus, we have successfully managed to add a method to an in-built Ruby class.

Monkey Patching

Another feature of metaprogramming is monkey patching, where we can override the existing method of a class by opening the class and modifying the definition at runtime. For example, if you are using a third-party library that is conflicting with your class method, which leads to a bug, then in this case, we monkey patch that specific method of the class.

Monkey patching is a debatable concept since it places tremendous power in the hands of developers and should be used very carefully, and only in situations where it is really required. Let's now look at an example of monkey patching in order to understand it practically.

An array class in Ruby is an in-built class and includes many out-of-the-box methods. An out-of-the-box feature or functionality (also called OOTB, or off-the-shelf), particularly in software, is a feature or functionality of a product that works immediately, without any special installation, without any configuration, or without modification.

One of the methods most commonly used is size, which returns the size of an array.

Now, let's try to monkey patch this method:

my_array = ["Hello", "World"]

puts my_array.size

Executing this file from the Terminal will provide the following result:

Figure 10.2: Array object size

This was the expected result, since the size of this array object, my_array, is clearly 2. However, imagine we have a requirement where we must always increment the size of an array by 3 for our program. In order to meet such a requirement, we can monkey patch the size method of the Ruby array class using the following code:

class Array

  def size

    self.length + 3

  end

end

my_array = ["Hello", "World"]

puts my_array.size

The output should be as shown in the following screenshot:

Figure 10.3: Monkey patching

Figure 10.3: Monkey patching

Here, we are overriding the in-built size method and adding 3 to whatever result we get using another array method length.

Now, the Ruby program for array object sizes has a new definition, everywhere. This was a very straightforward example to facilitate an understanding of monkey patching.

Let's now add an error to see how much damage incorrect code can do to an in-built class.

We will now add some logic to divide the integer value 1 by 0, which would result in an error:

class Array

  def size

    1/0

  end

end

my_array = ["Hello", "World"]

puts my_array.size

$ ruby monkey_patch_error.rb

The output would appear as follows:

Figure 10.4: Monkey patching

Figure 10.4: Monkey patching

Here, you can see the implementation of incorrect logic using monkey patching and how this would spoil this class for this Ruby program.

Exercise 10.02: Using Monkey Patching to Add/Subtract Values

In this exercise, we will create a program that would add the value 2 to any number passed. Then, we will monkey patch the same class to subtract the value 2 from any number passed to it. The following steps will help you to complete this exercise:

  1. Define the calculation class. It is initialized with first_number, which is used to set the initial value for objects in the calculation class. Next, we have a method, sum, that adds 2 to the value set in first_number:

    class Calculation

      attr_accessor :first_number

      def sum

        self.first_number + 2

      end

    end

  2. Next, we initialize the object of this class:

    calc_obj1 = Calculation.new

    calc_obj1.first_number = 10

    puts calc_obj1.sum

  3. Next, we monkey patch the sum method of the calculation class by opening the class:

    class Calculation

      def sum

        self.first_number - 2

      end

    end

    Note that we only had to modify the definition of the sum method, while the initialization of first_number stays as it is in the original class definition.

    We are subtracting 2 from the initial value, which is set using the sum method.

  4. Next, we initialize the object of the class:

    calc_obj2 = Calculation.new

    calc_obj2.first_number = 10

    puts calc_obj2.sum

    The output should be as follows:

    Figure 10.5: Output for monkey patching

Figure 10.5: Output for monkey patching

It is amazing when you first discover that you can modify methods right in the core classes, but monkey patching executed incorrectly can render the program a train wreck. Always think through the edge cases in the case of monkey patching. It is advisable to avoid using monkey patching for core classes and libraries. Its application is preferred in relation to classes created on your own.

method_missing

method_missing is an important tool in the toolbox of Ruby metaprogramming. It is a callback method you can use that gets called when an object tries to call a method that is missing.

Imagine you have created a class that has two methods, and, in your program, you call a method that does not exist in the class. Since this method is not present, then the search moves up the hierarchy, eventually reaching BasicObject.

In BasicObject, there is a private method called method_missing. The system now cycles through one more time to look for method_missing in our class and checks whether there are any matches for method_missing to produce the desired result.

Essentially, in our class, we are simply overriding method_missing from BasicObject.

Let's understand this with a simple example by creating a MyClass class with no method. Initialize its object, obj1, and call the xyz method, which does not exist:

class MyClass

end

obj1 = MyClass.new.xyz

Run this code from the Terminal:

$ ruby method_missing_basics.rb

The output should be as follows:

Figure 10.6: NoMethodError

Figure 10.6: NoMethodError

It is quite clear that we have no method as xyz in MyClass, which we can use with the object, obj1.

Let's now modify our class and add method_missing to it:

class MyClass

  def method_missing(method_name, *args, &block)

    puts "The method you have specified #{method_name} does not exist"

  end

end

obj1 = MyClass.new.xyz

Run this code from the Terminal:

$ruby method_missing_basics.rb

The output should be as follows:

Figure 10.7: Output for method_missing

Figure 10.7: Output for method_missing

When we modified our code and added method_missing, we did get a puts statement placed in the method instead of giving an undefined error method.

Let's now understand some of the various parameters accepted by method_missing:

def method_missing (method_name, *args, &block)

end

  • method_name: This is the name of the method you are calling.
  • *args: These are splat arguments passed to the method.
  • &block: This is the block of code that defines the functioning of the method.

If you look closely at these three parameters, we can create a method dynamically at runtime, which helps us to create code that creates code, and that is why method_missing is a key feature of metaprogramming.

Note

Methods defined using method_missing are also known as ghost methods, as there are an endless number of such methods and all can be tackled by defining and responding to calls via method_missing.

Whenever we override method_missing, it's a good practice to also define respond_to_missing?. This method is called when respond_to? is called.

respond_to? is a commonly used method and, if a ghost method exists, it should return true. However, if we do not define respond_to_missing?, the computer will return false, even though the missing method is defined.

Let's now look at the following example, where we define a class, MyClass, as having the method_missing method defined for the method, xyz, which returns a string. However, this method does not have respond_to_missing? defined:

class MyClass

  def method_missing (method_name, *args, &block)

    if method_name.to_s == "xyz"

        puts "You are now in ghost method"

    else

        super

    end

  end

end

obj1 = MyClass.new

obj1.xyz

puts obj1.respond_to?(:xyz)

Run this file from the Terminal with the following command:

$ ruby respond_to_missing_basics.rb

The output should be as follows:

Figure 10.8: Ghost method

Figure 10.8: Ghost method

Please note that even though we have method_missing defined for the method, xyz, we still get a false value for respond_to?.

Let's also define respond_to_missing? for any ghost method that starts with an x:

class MyClass

  def method_missing(method_name, *args, &block)

    if method_name.to_s == "xyz"

        puts "You are now in ghost method"

    else

        super

    end

  end

  def respond_to_missing?(method_name,  include_private = false)

    method_name.to_s.start_with?('x') || super

  end

end

obj1 = MyClass.new

obj1.xyz

puts obj1.respond_to?(:xyz)

Run this file from the Terminal using the following command:

$ ruby respond_to_missing_basics.rb

The output should be as follows:

Figure 10.9: Output for respond_to_missing

Figure 10.9: Output for respond_to_missing

Now, we get an appropriate response to the respond_to? method.

Exercise 10.03: Managing Ghost Methods for the Company Class

In this exercise, we will be creating a company class that includes employee details, such as name, ID, and location, using the in-built ostruct library. We will be implementing method_missing to give an appropriate response to methods that start with employee_:

  1. Create a new Ruby file.
  2. Then, we require the ostruct library from the in-built Ruby libraries:

    require 'ostruct'

  3. Next, we create a Company class and define the variables – name, ID, and location, within the class:

    class Company

      def initialize(name, id, location)

        @name = name

        @id = id

        @location = location

      end

  4. Next, we define the employee and also the new_employee methods in the same class:

      def employee

        OpenStruct.new(name: @name, id: @id, department: @location)

      end

    end

    new_employee = Company.new("Akshat", "007", "Tokyo")

    puts new_employee.employee_location

    puts new_employee.respond_to?(:employee_location)

  5. Let's run this program to see the result. Type the following command from the Terminal:

    $ruby exercise3.rb

    The output should be as follows:

    Figure 10.10: Undefined method error

    Figure 10.10: Undefined method error

    As you can see, we see an error because we are calling a method on the company class object that does not exist. If you look closely, the error itself is indicating to us that there is no method like this, and so we should create one.

    We have created an object of the company class and then called the employee_location method. However, that method does not exist and so the program breaks. We have also called a respond_to method on new_employee.

    If you replace this with the employee_location method when called, you will get a false value since no respond_to_missing? method exists.

  6. We will handle all ghost methods that start with employee_. Update the code in this file with the following method_missing and respond_to_missing? methods:

    Exercise10.03.rb

    14   def method_missing(method_name, *args, &block)

    15     if method_name.to_s =~ /employee_(.*)/

    16         employee.send($1, *args, &block)

    17     else

    18         super

    19     end

    20   end

    21 

    22   def respond_to_missing?(method_name, include_private = false)

    23     method_name.to_s.start_with?('employee') || super

    24   end

    25 end

    Here, we are using regular expressions for matching. Regular expressions help us to match a pattern for a string. The pattern should be between the forward slashes (/).

    For example, in the preceding code, we are using /employee_(.*)/, so anything starting with employee_ will be matched. The $ variable will retain the information about the last match.

  7. Let's run this program to see the result. Type the following command from the Terminal:

    $ ruby exercise3.rb

    The output should be as follows:

    Figure 10.11: Output for method_missing and respond_to_missing

Figure 10.11: Output for method_missing and respond_to_missing

We have now achieved the desired result. We sent employee_location, hence, we got the location as Tokyo in our result. Had we called a ghost method, employee_age, we would have not obtained any result. Play around by creating more ghost methods to see whether there are any changes in the results.

The Define Method

Similar to method_missing, define_method helps us to create methods dynamically at runtime. Hence, it qualifies as a tool in Ruby's metaprogramming toolbox. Essentially, define_method works in tandem with method_missing to make the code DRY (Do-not Repeat Yourself), where, instead of using def, we use define_method.

Let's look at its syntax:

class Factory

  define_method("operate_machinery") do |argument|

    "Starting machines on all assembly lines in #{argument}"

  end

  define_method("package_products") do |argument|

    "Packaging #{argument} products "

  end

  define_method("send_for_distribution") do |argument|

    "Sending for distribution for #{argument}"

  end

  define_method("generate_exit_pass") do |argument|

    "Generate exit pass for #{argument}"

  end

end

  factory = Factory.new

  puts factory.operate_machinery("Manchester")

  puts factory.package_products("healthcare")

  puts factory.send_for_distribution("medical stores")

  puts factory.generate_exit_pass("trucks")

If you look here, we have a different syntax for defining a method instead of def and end; we are using define_method and end. In the preceding code snippet, we have a class, Factory, that has various define_method methods that return a statement along with the argument passed.

Let's run this program to see the output. Run the following command from the Terminal:

$ ruby define_method_basics.rb

The output should be as follows:

Figure 10.12: Using define_method

Figure 10.12: Using define_method

define_method is best used with lists where we can loop around a list and place define_method in it to keep creating methods when called. We will learn about this in the next exercise.

Exercise 10.04: Creating a Welcome Message Program Using define_method

In this exercise, we will create a Ruby program that will deliver a welcome message to customers across five countries: France, Japan, England, Germany, and Brazil:

  1. Create a new Ruby file, exercise.rb.
  2. Create a WelcomeMessage class, which has a number of methods that will be generated using a list. We loop over this list and, using the list value, generate methods with the help of define_method:

    class WelcomeMessage

      countries = %w(fr jp eng de br)

      countries.each do |country|

        define_method("message_for_#{country}") do |argument|

          "Welcome to Ruby Fundamentals, this is a reader from #{argument}."

        end

      end

    End

  3. Outside the class, we create a class object and call various methods, passing the name of the country as an argument. In the define method, we are making use of the list value and argument passed while calling to get the desired results:

    greeting = WelcomeMessage.new

    puts greeting.message_for_fr("France")

    puts greeting.message_for_jp("Japan")

    puts greeting.message_for_eng("England")

    puts greeting.message_for_de("Germany")

    puts greeting.message_for_br("Brazil")

  4. Run the preceding code using the following command from the Terminal:

    $ ruby exercise.rb

    The output should be as follows:

    Figure 10.13: Output for define_method

Figure 10.13: Output for define_method

HTTP Requests

HTTP (Hypertext Transfer Protocol) is used to make requests and receive responses over the internet. HTTP helps in transferring data from one point to another over a network.

Such requests are most common when you interact with an external server, or APIs, to receive data or submit data to them. Essentially, no real-world applications are possible without making HTTP requests The most common way of organizing APIs is to use the constraints set by REST. REST (REpresentational State Transfer) is an architectural type that has prescribed standards for various systems to communicate with one another. These APIs are characterized by the separation of concerns between client and server (for example, if we make a Ruby program that interacts with an API, our program with the client and API to which the request is made will be the server).

For now, we will not go into detail about REST, but we will learn how to use it and how easy it makes it to interact with backend APIs.

With REST, there is a proper structure to make a request that generally comprises the following:

  • An HTTP verb; these are methods that define what operation should be performed (get, submit, update, or destroy the data)
  • A header, information that tells which client passed information about the request
  • The path of the resource
  • An optional message body that contains additional data

There are five commonly used HTTP verbs that are used to interact with resources when making a request in REST:

  • GET: The HTTP GET verb is used to react to or retrieve data from a resource.
  • POST: The HTTP POST verb is used to create a new resource.
  • PUT: The HTTP PUT verb is used to update a specific resource.
  • PATCH: The HTTP PATCH verb is used to modify a resource, but not completely. This looks similar to PUT, but there is a slight difference in that the PATCH body also contains a set of instructions.
  • DELETE: The HTTP DELETE verb is used to remove a resource by ID.

HTTP Requests with Ruby

Ruby has an in-built HTTP client called net/http. An HTTP client helps to make various types of HTTP requests using one of the methods explained previously, along with the URL and payload if required. The payload is a set of data that may be required by an external server to take some sort of action; for example, in the case of a search request, the payload could be the search keyword we have punched in the text field and then submitted. Using the in-built net/http package, you can make an HTTP request right away.

Let's see how a GET request will look with net/http. Let's first understand the syntax of a GET request with Ruby's net/http library:

require 'net/http'

Net::HTTP.get('example.com', '/index.html')

This is a simple GET request made using net/http, where we are trying to get a complete index.html page from http://example.com. Usually, we save this response and copy the relevant data from it. This technique is used in web scraping to harvest huge amounts of data from other internet websites.

Exercise 10.05: Creating a Ruby Program to Make a Successful GET Request

In this exercise, we will use the Ruby net/http library and make use of the https://www.packtpub.com URL to get the data:

  1. Create a new Ruby file, http_get.rb.
  2. First, we require the net/http library from the Ruby in-built package:

    require 'net/http'

  3. Place the URL in the URI method, which is a Ruby module that assists in handling web URLs in Ruby:

    uri = URI('https://www.packtpub.com')

  4. Next, we make a GET request using this URL and keep the object in a variable response. If the response object has a lot of data, we then print its status code and body using the response.code and response.body methods, respectively:

    response = Net::HTTP.get_response(uri)

    puts response.code

    puts response.body

  5. Let's now run this Ruby program from the Terminal:

    $

    ruby http_get.rb

    The output should be as follows:

Figure 10.14: Get Requests using Ruby

Figure 10.14: Get Requests using Ruby

As we can see, with response.code, we received the status code 200 for our request from the server, and with response.body, we received the data from the GET request we made.

Status Codes

Status codes are provided from the server side, which is in response to a client request made. HTTP status codes are divided into five categories. The first digit of the code defines the class of response. The last two digits do not have any specific class or categorization. The first digit is key to understanding the state of your request. Listed here are five types of status codes:

1xx: Informational

This means that the client request has been received and the process is continuing. This is a client-side status code, and is mainly informational.

2xx: Success

This means that the client request was successfully received, understood, and accepted.

3xx: Redirection

This means that further action must be taken in order to complete the request.

4xx: Client Error

This status code is received in case there has been an error from the client. This means that the request contains incorrect syntax or cannot be fulfilled.

5xx: Server Error

This means that the server failed to fulfill an apparently valid request. This status code indicates that the server is incapable of completing the requests.

Note

Read more on status codes here: https://packt.live/2OP9Rtr.

Exercise 10.06: Creating a POST Request Using Ruby

In this exercise, we will be generating a POST request using the Ruby gem, httparty, which simplifies the submission of complicated requests.

Use the following demo URL, https://my-json-server.typicode.com/typicode/demo/posts, to make the request.

For parameters of the POST request, use the following format:

body: {

id: integer_id, title: ""

  }

The following steps will help you to complete the exercise:

  1. Create a new Ruby file, http_post.rb.
  2. Install the httparty gem using the following command from the Terminal:

    $ gem install httparty

    This will install the gem on your system, and you can require it in any Ruby program.

    Note

    To find out more about this gem, you can refer to its documentation at https://packt.live/2MfSm42.

  3. Now, we require the httparty gem in the program:

    require 'httparty'

  4. Next, we make a post call using a sample API from my-json-server (this is a valid API and will work, unless the parameters passed won't get persisted):

    res = HTTParty.post("https://my-json-server.typicode.com/typicode/demo/posts", body: { id: 5, title: "Ruby Fundamentals" })

  5. Then, we check the status code received and also the body for the response, which is usually the resource created:

    puts res.code

    puts res.body

  6. Let's now run this Ruby program from the Terminal:

    $ ruby http_post.rb

    The output should be as follows:

Figure 10.15: Post request output

Figure 10.15: Post request output

As you can see, the output is very clean. We received status code 201. Since it starts with a 2, it means we have succeeded, and 201 indicates precisely that the resource has been created. The response body is the value of the data that is used to create the request.

Creating a Ruby Gem

As covered in Chapter 7, Introduction to Ruby Gems, a gem is a way for Ruby to package and distribute Ruby programs and libraries. So far, we have been using many open source Ruby gems, which has a positive impact on the speed of development.

In this section, we will learn to create a Ruby gem. Also, RubyGems is a package manager for the Ruby programming language and comes with tools baked in by default, which makes it really easy to create a gem and distribute it.

Let's jump right in to creating a simple Ruby gem.

Before you create your first file for your gem, you must make sure to find a suitable name for your gem. RubyGems has official documentation for naming conventions and it is advised to use this for improved programming experiences.

Note

You can refer to this naming convention at https://packt.live/2Bcz1dN.

Exercise 10.07: Creating Your Own Ruby Gem

In this exercise, we will be creating our own Ruby gem, before installing it and then publishing it in a Ruby program:

  1. Create two files, namely, ruby-fundamental-gem.rb and ruby-fundamental-gem.gemspec under the lib folder, and place them in a directory, as shown in the following screenshot:
    Figure 10.16: Creating Ruby gem files

    Figure 10.16: Creating Ruby gem files

    The code that will be used for our package will reside in the lib directory. A good practice is to have one Ruby file with the same name as the gem since, in our case, it will be required as ruby-fundamental-gem.

  2. Now, we create a class, RubyFundamental, and define a method:

    class RubyFundamental

      def self.hello

        puts "Hello World this is my first gem!"

      end

    end

  3. Next, we move to the ruby-fundamental-gem.gemspec file. This file contains information about the gem; for example, the creator, its version number, the contact details for the core team or whoever maintains the gem, and the license:

    Gem::Specification.new do |s|

      s.name        = 'ruby-fundamental-gem'

      s.version     = '0.0.1'

      s.date        = '2019-06-30'

      s.summary     = "Simple gem to learn how to create gems"

      s.description = "A basic welcome message gem"

      s.authors     = ["Akshat Paul"]

      s.email       = '[email protected]'

      s.homepage    = %q{http://www.akshatpaul.com/}

      s.files       = ["lib/ruby-fundamental-gem.rb"]

      s.license     = 'MIT'

    end

  4. Once you have filled in the basic specifications for the gem, build and install this generated gem locally. Run the following command from the Terminal:

    $ gem build ruby-fundamental-gem.gemspec

    The output should be as follows:

    Figure 10.17: Creating a gem

    Figure 10.17: Creating a gem

  5. Now, install this gem locally, which we can then use with any Ruby program locally without a machine. Run the following command from the same folder on the Terminal:

    $ gem install ruby-fundamental-gem-0.0.1.gem

    The output should be as follows:

    Figure 10.18: Installing a Ruby gem

    Figure 10.18: Installing a Ruby gem

    Our gem is successfully installed. Now, let's try using this gem by requiring it. Open IRB and use the following code to test it:

    $ irb

    require 'ruby-fundamental-gem'

    RubyFundamental.hello

    The output should be as follows:

    Figure 10.19: Requiring a Ruby gem

    Figure 10.19: Requiring a Ruby gem

    We have now successfully installed the gem.

  6. Publish this gem on the Ruby community; it will be available for use worldwide.

    Log in and set up your credentials using the https://rubygems.org/sign_up URL.

  7. Download your api_key, which will be used to publish any gem using the following URL: https://rubygems.org/api/v1/api_key.yaml.

    Simply paste this URL in the browser. You will be prompted to add your credentials and the key will start downloading automatically.

  8. Create a .gem folder in your RubyGem package and add this file but rename it as credentials.yaml.

    Run the following command to publish your gem:

    $ gem push gem_name.gem

Thus, we have successfully created our own Ruby gem and published it for the world to use.

Activity 10.01: Implementing GET and POST Data to an External Server

In this activity, we will be creating a Ruby program to get JSON data from a public API, and then parse and print the response. Also, we will post new data to the public API.

The public APIs to be used for this activity are as follows:

Note that the second link will become functional only after the activity is completed. To post data using the preceding backend API, only the name and address fields are required to create new records like this:

{

property: {

name: "my_name", require 'ostruct'

address: "my_address"

}

}

The following steps should help you to complete this activity:

  1. Install and require the httparty gem.
  2. Create a file for GET requests. Assign a GET request API to a URL variable.
  3. Next, make a GET call using httparty and display the response using an in-built method, parsed_response, which properly parses the JSON response.

    You can implement the same code with a few more lines by using the in-built net/http library and the JSON library.

    The output should be as follows:

    Figure 10.20: GET request output

    Figure 10.20: GET request output

  4. Create a file for POST requests.
  5. Next, assign our POST API to the URL variable. Make a POST request, along with the URL and a body with proper fields, as per the contract specified in the problem statement.

    The output should be as follows:

    Figure 10.21: POST request output

    Figure 10.21: POST request output

  6. Check and verify whether the records exist in both the aforementioned URLs.

    Note

    The solution to the activity can be found on page 486.

Summary

In this chapter, we learned skills that are commonly used in real-world problems, such as metaprogramming, communicating with backend APIs, and creating reusable gems. No Ruby framework or open source library is complete without making use of a lot of metaprogramming. We learned various techniques as well as some of the in-built features of Ruby, including open class, method_missing, respond_to_missing?, monkey patching, and define_method. Next, we learned how to make HTTP requests to interact with external APIs over a network. Lastly, we learned how to package and distribute our reusable code by creating gems ourselves.

In the next chapter, we will learn about the most popular Ruby framework or, should we say, one of the world's most widely used server-side web application frameworks – Ruby on Rails.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.223.237.131