Fadi Fadi - 2 months ago 9
Ruby Question

Loop through variables in different classes to match string in Ruby

I have a ruby (sinatra) app that I am working on, and my input is a url and if verbose or not (true or false), so basically like this:

The url would look like this:

http://localhost:4567/git.company.com&v=false
for example.

And the code to fetch those is this:

get '/:url' do |tool_url|
url = params[:url].to_s
is_verbose = params[:v].to_s


I have different classes separated in different files and I'm including them into my main script like this:

Dir["#{File.dirname(__FILE__)}/lib/*.rb"].each { |f| require(f) }


(And a sample file would be something like this),
gitlab.rb
:

class Gitlab
$gitlab_token = 'TOKEN_GOES_HERE'
def initialize(url, v)
@@regex =~ /git.company.com/
@@gitlab_url = url
@@is_verbose = v
end

def check_gitlab(gitlab_url, is_verbose)
_gitlab_overall = '/health_check.json?token=#{gitlab_token}'
_gitlab_cache = '/health_check/cache.json?token=#{gitlab_token}'
_gitlab_database = '/health_check/database.json?token=#{gitlab_token}'
_gitlab_migrations = '/health_check/migrations.json?token=#{gitlab_token}'
unless is_verbose = true
CheckString.check_string_from_page('https://' + gitlab_url + gitlab_overall, 'success')
else

end
end
end


Now, I want to be able to dynamically know which "class" to use to do a certain job based on the URL that's entered by the user, so my idea was to iterate through those classes looking for a particular variable to match with the input.

I need guidance in this because I've been stuck on this for quite some time now; I've tried so many things that I can think of, but none worked.

Disclaimer: Please bear with me here, because I'm very new to Ruby and I'm not that great in OOP languages (haven't really practiced them that much).

EDIT: I'm open to any suggestion, like if there's a different logic that's better than this, please do let me know.

Answer

Make a hash { Regexp ⇒ Class }:

HASH = {
  /git.company.com/ => Gitlab,
  /github.com/ => Github
}

and then do:

handler = HASH.detect { |k, _| k =~ url }.last.new

The above will give you an instance of the class you wanted.

Sidenotes:

  • is_verbose = params[:v].to_s always results in is_verbose set to truthy value, check for params[:v].to_s == true
  • is_verbose = true is an assignment, you wanted to use just unless is_verbose.

To make it runtime-resolving, force the plugins to a) include Plugin and b) declare resolve method. Plugin module should define a callback hook:

module Plugin
  def self.included(base)
    Registry::HASH[-> { base.resolve }] = base
  end
end

resolve method should return a regexp, the lambda id here to make it resolved on parsing stage:

class PluginImpl
  include Plugin
  def resolve
    /git.company.com/
  end
end

And then match when needed:

handler = HASH.detect { |k, _| k.() =~ url }.last.new

Other way round would be to use ObjectSpace to detect classes, including the module, or declare the TracePoint on base in included callback to provide a direct map, but all this is overcomplicating.