Small code refactor - Moriarty part-2
Tags: ruby, beginners, opensource, tutorial
Published: 2021-04-02 01:40:56

{% github decentralizuj/moriarty %}

First code is never good enough, especially in Ruby, where everything could be done in many different ways. I'll start with initializer:

```ruby
  # Set username and site for search request
  # exclude 'https', #make_url will add it for you
  # To use different protocol, set it as third parameter
  #
  # @jim = Moriarty.new( :moriarty, 'example.com', :http )
  #  => @jim.user == 'moriarty'
  #  => @jim.url  == 'http://example.com/'

  def initialize( name = '', site = 'github.com', prot = :https )
    @user = name.to_s
    @url  = make_url site, prot
  end
```  

Here we added 'make_url(site_name, protocol)'. This method purpose is to construct `URL` from string, so we can use `dev.to` instead of `https://dev.to`.

```ruby
  # create URL from site name, add 'https' if needed
  # @jim.make_url 'github.com'
  #  => 'https://github.com/'

  def make_url( link, prot = :https )
    prot = nil if link.to_s.start_with? prot.to_s
    url  = prot.nil? ? link.to_s : prot.to_s + '://' + link.to_s
    url += '/' unless url.end_with?('/')
    return url
  end
```  

Here we can add parameter `site: github.com` in `Moriarty#go`, without `https://`. In first part I said that we'll create _setters_ manually. Now we can use `#make_url` in setter to create link from string. 

```ruby
  # Set URL from site name and protocol(optional)
  # @jim.url = 'github.com'
  #  => @jim.url == 'https://github.com'

  def url=( link, prot = :https )
    @url = make_url link, prot
  end

  # Set username from string or :symbol
  # @jim.user = :moriarty
  #  => @jim.user == 'moriarty'

  def user=( name )
    @user = name.to_s
  end
```  

It's time to edit `Moriarty#go`, method in charge to send request.

```ruby
  # execute request (args are optional)
  # @jim.go site: 'github.com', user: 'mynickname'
  #  => true/false
  #  -> @jim.response (.code, .headers, .body)
  #  -> @jim.html (page HTML if request success)

  def go( opt = {} )

    # define username to search, or use default
    opt[:user] ||= @user

    # if option 'site:' is 'nil', use default
    # otherwise construct url with '#make_url'
    url = opt[:site].nil? ? @url : make_url(opt[:site])

    # create url for request, and send
    uri = url + opt[:user]
    @response = RestClient.get uri

    # try to scrap data from page
    @html     = Nokogiri::HTML @response

    # return true or false
    return @success = true
    rescue
    return @success = false
  end

  # add alias search, just because of convention
  alias search go
```  

There's one more thing that we should add here, to check for response _success:_

```ruby
  # Check does request succeeded or not
  # @jim.success?
  #  => true/false

  def success?
    @success == true
  end
```  

Create method to execute search request, and output data in terminal. Default method is search for free username, in that case _fail_ requests mean username is free. If we define `:hunt` as _type parameter,_ we will search for registered user.

```ruby
  # Find method is responsible to handle all other methods
  # and to tell use final results

  def find!( user = @user, web = @url, type = :search )

    @jim.go user: user, site: site

    name = print_name(user).to_s
    site = print_url(web).to_s

    case    
    when type.to_sym == :hunt && @jim.success?
      puts "#{name} found on #{site}"

    when type.to_sym == :hunt && !@jim.success?
      puts "#{name} not found #{site}"

   when @jim.success?
      puts "#{name} is taken on #{site}"

    else
      puts "#{name} is free on #{site}"
    end
  end
```  

Methods `#print_name` and `#print_url` prepare strings for printing in cli. Names are cleaned from signs like `@, #, /u/`, and site is stripped of extensions and capitalized.

```ruby
  # Remove extensions from domain name
  # Moriarty.print_url('https://www.github.com')
  #  => 'github'

  def print_url( site )

    # define site from string
    # make name empty string
    site, name = site.to_s, ''

    # if site start with 'http', try to remove 'https'
    # if not, then remove 'http'

    if site.start_with?('http')
      site.gsub!("https://", '') or site.gsub!("http://", '')
    end

    # remove 'www.' from sitename, if included

    site.gsub!("www.", '') if site.start_with?('www.')

    # split domain on '.' to get extension, and remove it

    ext  = site.to_s.split('.').last
    name = site.gsub(".#{ext}", '')

    # if ext is longer then 5, routes contain more data
    # example: 'rubygems.org/profiles/*'

    name = name.split('/').first if ext.size < 5

    # first letter uppercase

    return name.capitalize

  end

  # Remove extensions from username
  # @jim.print_name('@moriarty') 
  #  => 'moriarty'

  def print_name( name )
    name.gsub!('@','') if name.to_s.start_with?('@')
    name.gsub!('#','') if name.to_s.start_with?('#')
    name.gsub!('/u/','') if name.to_s.start_with?('/u/')
    return name
  end
```  

Now we have `class` with all objects needed to do what we want it to do. For sites that need to check `html` for success (like twitter), there's variable @html ( getter Moriarty.html ). 

Let's run search from terminal. How? We need to define sites to search, and usernames. We'll define sites as array, and accept usernames as arguments. If we add `--hunt`, it will run in hunt mode, otherwise in default (search for free name).

```ruby
  # define sites to search

  SITES = [ 'github.com', 'dev.to' ].freeze

  # run hunt if arg --hunt included, otherwise search

  hunt = ARGV.include?('--hunt') ? :hunt : :search

  unless ARGV.empty?

    @jim = Moriarty.new :jim

    ARGV.each do |user|
      SITES.each do |site|

        next if user == '--hunt'
        @jim.find! user, site, hunt

      end
    end

  end
```  

Thanks all for reading this post(s), don't forget to share content...somewhere :) In next article I'll pack and compile this into a gem.