Is multiple include?() arguments in ruby possible? - ruby

def coffee_drink?(drink_list)
drink_list.include?("coffee") ? true : drink_list.include?("espresso") ? true : false
end
I am learning Ruby with TOP and am looking to check for more than a single argument with the include function. I don't think my solution is too bad but surely there is a better solution I am just unable to find.
e.g. include?("ABC", "CBA) and include?("ABC" || "CBA") wont work.

def coffee_drink?(drink_list)
%w(coffee espresso).any? { |drink| drink_list.include?(drink) }
end
or
def coffee_drink?(drink_list)
(%w(coffee espresso) & drink_list).any?
end
note that your version could be rewritten like this
def coffee_drink?(drink_list)
drink_list.include?("coffee") || drink_list.include?("espresso")
end

Related

Accessing local variables in the calling context

In my code, i have several methods using the following pattern
def my_method only: [], ignore: []
something('textvalue') if (only.empty? && ignore.empty?) || (only.any? && only.include?('textvalue')) || (ignore.any? && !ignore.include?('textvalue'))
end
In other word, i can choose to filter the results either by specifying only or ignore, depending on which one is more convenient in the context.
I would like a way to declare a helper want that access the onlyand ignore local parameters without having to specify them each time, the result would ideally look like this:
def my_method only: [], ignore: []
something('textvalue') if want('textvalue')
end
This helper would be used in several different methods, classes, etc. It would somehow check the local variables at the calling point, validate that only and ignore exists, and then check if the parameter is wanted or not.
Is it possible to access the calling stack and look at the local variables there?
There is a gem binding_of_caller which can do this. Install the gem and then do
require 'binding_of_caller'
def my_method only: [], ignore: []
something('textvalue') if want('textvalue')
end
def want(value)
only = binding.of_caller(1).local_variable_get(:only)
ignore = binding.of_caller(1).local_variable_get(:ignore)
(only.empty? && ignore.empty?) || (only.any? && only.include?(value)) || (ignore.any? && !ignore.include?(value))
end
But this is a bad thing to do as it creates very high coupling. It's really not good design. If you want to do this for experimentation and playing around, fair enough, but don't do it in production.
You can use ruby method definition to do this
def my_method val, only: [], ignore: [], want: ->(val) { ((only.empty? && ignore.empty?) || (only.any? && only.include?(val))) }
something(val) if want.call(val)
end
my_method 'value', only: ['value2']
=> false
In circumstances such as this, couldn't you just pass the args to want?
def my_method only: [], ignore: []
something('textvalue') if want?('textvalue', only, ignore)
end
def want?(string, only, ignore)
(only.empty? && ignore.empty?) || (only.any? && only.include?(string)) || (ignore.any? && !ignore.include?(string))
end
Doesn't seem to be any need for it to be more complex than that?
That is a lot simpler to manage and for others to deal with going forward - which I'd consider far more important than avoiding passing a couple of args to a method.

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.
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 is 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.

undefined method error in ruby selenium

I am using ruby with selenium and my code is as follows:
$num=1
def isElementPresent(xpathExpression)
allElements=#driver.find_elements(:xpath,xpathExpression)
if (allElements.size==0)
return true
end
else
return false
end
while Demo.isElementPresent(str1+$num.to_s+str2)
text=#driver.find_element(:xpath,str1+$num.to_s+str2).text
$num+=1
puts "text is:#{text}"
#driver.find_element(:xpath,str1+$num.to_s+str2).click
puts #driver.title
#driver.navigate.back
end
end
I'm getting an undefined method error for while Demo.isElementPresent(str1+$num.to_s+str2).
Any help is appreciated
As per my understanding, Your condition should be:
if (allElements.size>0)
return true
As if size is 0. That means no element is present.
Also, in this case your function definition should end before you are calling it.
Try following code:
$num=1
def isElementPresent(xpathExpression)
allElements=#driver.find_elements(:xpath,xpathExpression)
if (allElements.size>0)
return true
end
else
return false
end
end
while isElementPresent(str1+$num.to_s+str2) do
text=#driver.find_element(:xpath,str1+$num.to_s+str2).text
$num+=1
puts "text is:#{text}"
#driver.find_element(:xpath,str1+$num.to_s+str2).click
puts #driver.title
#driver.navigate.back
end
Here I have made two changes: First, for the condition I explained about and Second, Ending the definition of function before your loop.
Please let me know if it works as intended.

Using Ruby to parse and write Puppet node definitions

I am writing a helper API in Ruby to automatically create and manipulate node definitions. My code is working; it can read and write the node defs successfully, however, it is a bit clunky.
Ruby is not my main language, so I'm sure there is a cleaner, and more rubyesque solution. I would appreciate some advice or suggestions.
Each host has its own file in manifests/nodes containing just the node definition. e.g.
node 'testnode' {
class {'firstclass': }
class {'secondclass': enabled => false }
}
The classes all are either enabled (default) or disabled elements. In the Ruby code, I store these as an instance variable hash #elements.
The read method looks like this:
def read()
data = File.readlines(#filepath)
for line in data do
if line.include? 'class'
element = line[/.*\{'([^\']*)':/, 1]
if #elements.include? element.to_sym
if not line.include? 'enabled => false'
#elements[element.to_sym] = true
else
#elements[element.to_sym] = false
end
end
end
end
end
And the write method looks like this:
def write()
data = "node #{#hostname} {\n"
for element in #elements do
if element[1]
line = " class {'#{element[0]}': }\n"
else
line = " class {'#{element[0]}': enabled => false}\n"
end
data += line
end
data += "}\n"
file = File.open(#filepath, 'w')
file.write(data)
file.close()
end
One thing to add is that these systems will be isolated from the internet. So I'd prefer to avoid large number of dependency libraries as I'll need to install / maintain them manually.
If your goal is to define your node's programmatically, there is a much more straightforward way then reading and writing manifests. One of the built-in features of puppet is "External Node Classifiers"(ENC). The basic idea is that something external to puppet will define what a node should look like.
In the simplest form, the ENC can be a ruby/python/whatever script that writes out yaml with the list of classes and enabled parameters. Reading and writing yaml from ruby is as simple as it gets.
Ruby has some pretty good methods to iterate over data structures. See below for an example of how to rubify your code a little bit. I am by no means an expert on the subject, and have not tested the code. :)
def read
data = File.readlines(#filepath)
data.each_line do |line|
element = line[/.*\{'([^\']*)':/, 1].to_sym
if #elements.include?(element)
#elements[element] = line.include?('enabled => false') ? false : true
end
end
end
def write
File.open(#filepath, 'w') do |file|
file.puts "node #{#hostname} {"
#elements.each do |element|
if element[1]
file.puts " class {'#{element[0]}': }"
else
file.puts " class {'#{element[0]}': enabled => false }"
end
end
file.puts '}'
end
end
Hope this points you in the right direction.

Simplifying an "any of" check with or-operator in Ruby

How to simplify the following check ?...
if node[:base][:database][:adapter].empty? || node[:base][:database][:host].empty? ||
node[:base][:database][:database].empty? || node[:base][:database][:port].empty?
to something like
required_keys = { :adapter, :host, :database...etc...}
required keys - node[:base][:database] == []
This syntax is a little off, but basically subtract the keys you have from the set of required keys. If you have all the required keys in your set, the result should be empty.
I am not sure regarding the correct syntax ? . Any help would be appreciated
required_keys = [:adapter, :host, :database ]
if required_keys.any?{|x| node[:base][:database][x].empty?}
#code here
end
Or you could do also:
node[:base][:database].values_at(*required_keys).any?(&:empty?)
If you think you're going to use this functionality multiple places, you can extend the Hash class and require the extension in an initializer.
class Hash
def contains_values_for?(*keys)
keys.all? do |key|
self[key].present?
end
end
end
Now you can do:
node[:base][:database].contains_values_for?(:adapter, :host, :database, :port)

Resources