CALABASH - Renaming screenshot filenames without the iterator - calabash

In Calabash you can take a screenshot and rename it to whatever you want and save it to any directory like so:
screenshot({:prefix => "some/directory", :name=>"some_name.png"})
However it will always save as some_name_0.png and the next one will be some_name_1.png.
Does anyone know how to rename the filename completely without the iterator?

You can also just pass text from your steps on what to save the screendump as.
I have done this to easily set the prefix and name and only take the screendumps when I add "capture=true" to the start command.
def take_picture(prefix, name)
if ENV["capture"] == 'true'
screenshot(options={:prefix=>prefix, :name=>name})
end
end
And from the steps I call it like this(this is example does not add special prefix:
take_picture("","SettingsMenu1")

In lib/calabash-cucumber/failure_helpers.rb the iterator is defined via ##screenshot_count ||= 0 then ##screenshot_count += 1
So I just overwrite that.

Related

How can I use regex to construct an API call in my Jekyll plugin?

I'm trying to write my own Jekyll plugin to construct an api query from a custom tag. I've gotten as far as creating the basic plugin and tag, but I've run into the limits of my programming skills so looking to you for help.
Here's my custom tag for reference:
{% card "Arbor Elf | M13" %}
Here's the progress on my plugin:
module Jekyll
class Scryfall < Liquid::Tag
def initialize(tag_name, text, tokens)
super
#text = text
end
def render(context)
# Store the name of the card, ie "Arbor Elf"
#card_name =
# Store the name of the set, ie "M13"
#card_set =
# Build the query
#query = "https://api.scryfall.com/cards/named?exact=#{#card_name}&set=#{#card_set}"
# Store a specific JSON property
#card_art =
# Finally we render out the result
"<img src='#{#card_art}' title='#{#card_name}' />"
end
end
end
Liquid::Template.register_tag('cards', Jekyll::Scryfall)
For reference, here's an example query using the above details (paste it into your browser to see the response you get back)
https://api.scryfall.com/cards/named?exact=arbor+elf&set=m13
My initial attempts after Googling around was to use regex to split the #text at the |, like so:
#card_name = "#{#text}".split(/| */)
This didn't quite work, instead it output this:
[“A”, “r”, “b”, “o”, “r”, “ “, “E”, “l”, “f”, “ “, “|”, “ “, “M”, “1”, “3”, “ “]
I'm also then not sure how to access and store specific properties within the JSON response. Ideally, I can do something like this:
#card_art = JSONRESPONSE.image_uri.large
I'm well aware I'm asking a lot here, but I'd love to try and get this working and learn from it.
Thanks for reading.
Actually, your split should work – you just need to give it the correct regex (and you can call that on #text directly). You also need to escape the pipe character in the regex, because pipes can have special meaning. You can use rubular.com to experiment with regexes.
parts = #text.split(/\|/)
# => => ["Arbor Elf ", " M13"]
Note that they also contain some extra whitespace, which you can remove with strip.
#card_name = parts.first.strip
#card_set = parts.last.strip
This might also be a good time to answer questions like: what happens if the user inserts multiple pipes? What if they insert none? Will your code give them a helpful error message for this?
You'll also need to escape these values in your URL. What if one of your users adds a card containing a & character? Your URL will break:
https://api.scryfall.com/cards/named?exact=Sword of Dungeons & Dragons&set=und
That looks like a URL with three parameters, exact, set and Dragons. You need to encode the user input to be included in a URL:
require 'cgi'
query = "https://api.scryfall.com/cards/named?exact=#{CGI.escape(#card_name)}&set=#{CGI.escape(#card_set)}"
# => "https://api.scryfall.com/cards/named?exact=Sword+of+Dungeons+%26+Dragons&set=und"
What comes after that is a little less clear, because you haven't written the code yet. Try making the call with the Net::HTTP module and then parsing the response with the JSON module. If you have trouble, come back here and ask a new question.

How to run a combination of query and filter in elasticsearch?

I am experimenting using elasticsearch in a dummy project in django. I am attempting to make a search page using django-elasticsearch-dsl. The user may provide a title, summary and a score to search for. The search should match all the information given by the user, but if the user does not provide any info about something, this should be skipped.
I am running the following code to search for all the values.
client = Elasticsearch()
s = Search().using(client).query("match", title=title_value)\
.query("match", summary=summary_value)\
.filter('range', score={'gt': scorefrom_value, 'lte': scoreto_value})
When I have a value for all the fields then the search works correctly, but if for example I do not provide a value for the summary_value, although I am expecting the search to continue searching for the rest of the values, the result is that it comes up with nothing as a result.
Is there some value that the fields should have by default in case the user does not provide a value? Or how should I approach this?
UPDATE 1
I tried using the following, but it returns every time no matter the input i am giving the same results.
s = Search(using=client)
if title:
s.query("match", title=title)
if summary:
s.query("match", summary=summary)
response = s.execute()
UPDATE 2
I can print using the to_dict().
if it is like the following then s is empty
s = Search(using=client)
s.query("match", title=title)
if it is like this
s = Search(using=client).query("match", title=title)
then it works properly but still if i add s.query("match", summary=summary) it does nothing.
You need to assign back into s:
if title:
s = s.query("match", title=title)
if summary:
s = s.query("match", summary=summary)
I can see in the Search example that django-elasticsearch-dsl lets you apply aggregations after a search so...
How about "staging" your search? I can think if the following:
#first, declare the Search object
s = Search(using=client, index="my-index")
#if parameter1 exists
if parameter1:
s.filter("term", field1= parameter1)
#if parameter2 exists
if parameter2:
s.query("match", field=parameter2)
Do the same for all your parameters (with the needed method for each) so only the ones that exist will appear in your query. At the end just run
response = s.execute()
and everything should work as you want :D
I would recommend you to use the Python ES Client. It lets you manage multiple things related to your cluster: set mappings, health checks, do queries, etc.
In its method .search(), the body parameter is where you send your query as you normally would run it ({"query"...}). Check the Usage example.
Now, for your particular case, you can have a template of your query stored in a variable. You first start with, let's say, an "empty query" only with filter, just like:
query = {
"query":{
"bool":{
"filter":[
]
}
}
}
From here, you now can build your query from the parameters you have.
This is:
#This would look a little messy, but it's useful ;)
#if parameter1 is not None or emtpy
#(change the if statement for your particular case)
if parameter1:
query["query"]["bool"]["filter"].append({"term": {"field1": parameter1}})
Do the same for all your parameters (for strings, use "term", for ranges use "range" as usual) and send the query in the .search()'s body parameter and it should work as you want.
Hope this is helpful! :D

Use ConfigParser with different variable types in Python

I am trying to use ConfigParser in the following situation. I am running some code after which i have an object with several attributes. I pick out some of these attributes and write them to a .ini file with configparser. This works fine and my .ini file looks something like this.
[Section]
path = "D:\\"
number = 10.0
boolean = False
Then with some other script I want to read the file and add the items as attributes to another object (self) using.
parser.read('file.ini')
self.__dict__.update(dict(parser.items("Section")))
This fails because all values are read as strings by configparser and now all attributes are strings. parser.items("Section") looks like this:
[('path', '"D:\\"'), ('number', '10.0'), ('boolean', 'False')]
Now I could go and specify the floats, integers, and booleans by their keys and use the corresponding methods parser.getfloat, getint, and getboolean to get the right python types out. However, that means making an extra list of keys and a loop to get them for each data type, which i don't want. Furthermore, even the path is now double quoted and i need to start removing quotes.
This behavior makes ConfigParser almost completely worthless to me and I am doubting if I am using it correctly an if ConfigParser is the best option for my goal, which is simply to write object attributes to a file and at a later time read the file and add the parameters to a new object as attributes. Can I use ConfigParser for this effectively? Or should I start looking for a different method?
INI is not JSON. There are no data types. There are sections and key/value pairs. Stuff before the = is the key, stuff after it is the value. Everything is text.
There are no "strings", which means there is no need to double quote anything. The same goes for "escaped" backslashes. The concept of escaping does not exist in the INI file format.
So, first off, your file should be looking like this:
[Section]
path = D:\
number = 10.0
boolean = False
Next, I consider this a dangerous operation
parser.read('file.ini')
self.__dict__.update(dict(parser.items("Section")))
because it potentially trashes your class instance with arbitrary values from a text file that might contain garbage, but when you can swear that the file will always be fine, well, do it if you must.
I would write a more explicit way of reading and validating config data. I sense your reason not to do that is laziness or a false sense of simplicity; both of these reasons are not very good.
If you want a semi-automated way of type conversion, tag the keys with a data type.
[Section]
s_path = D:\
f_number = 10.0
b_boolean = False
and write a function that knows how to handle them and throws when something is not right.
def type_convert(items):
result = []
for (key, value) in items:
type_tag = key[:2]
if type_tag == "s_":
result.append((key[2:], value))
elif type_tag == "f_":
result.append((key[2:], float(value)))
elif type_tag == "b_":
result.append((key[2:], bool(value)))
else:
raise ValueError('Invalid type tag "%s" found in ini file.' % type_tag)
# alternatively: "everything else defaults to string"
return result
which you can use to make the operation somewhat more convenient:
self.__dict__.update(dict(type_convert(parser.items("Section"))))
Of course you still run the risk of trashing your class instance by overriding keys that should not be overridden.

How to pass regular expression in a list in Groovy?

I have tried these things but it is not working for me:
def fileNames = [/ReadyAPI-\d.\d.\d.vmoptions/, 'loadtestrunner.bat', 'ready-api.bat', 'securitytestrunner.bat']
def fileNames = ['ReadyAPI-\\d.\\d.\\d.vmoptions', 'loadtestrunner.bat', 'ready-api.bat', 'securitytestrunner.bat']
What I am trying to do is that there will be one of the two files that will be present in the system which are:
'ReadyAPI-1.2.2.vmoptions' OR 'ReadyAPI-1.3.1.vmoptions'.
I am relatively new to Groovy so may be I am not seeing common problem. So, please bear with me. Thanks
You will need to get the filename first, then put it into the list. You can use Groovy's FileNameByRegexFinder from groovy.utils like this to find that file with a regex:
def optionsFile = new FileNameByRegexFinder()
.getFileNames('.', /ReadyAPI-\d.\d.\d.vmoptions/).first()
def fileNames = [optionsFile, 'loadtestrunner.bat', ...]
Note that the first parameter to getFileNames() is the base directory to search in, you will likely need to change that for your scenario.

Is there a way to check if part of the URL contains a certain string

Is there a way to check if part of the URL contains a certain string:
Eg. <% if current_spree_page?("/products/*") %>, where * could be anything?
I tested, and gmacdougall's answer works, I had already found a solution though.
This is what I used to render different layouts depending on what the url is:
url = request.path_info
if url.include?('products')
render :layout => 'product_layout'
else
render :layout => 'layout'
end
The important thing to note is that different pages will call different methods within the controller (eg. show, index). What I did was put this code in its own method and then I am calling that method where needed.
If you are at a place where you have access to the ActionDispatch::Request you can do the following:
request.path.start_with?('/products')
You can use include? method
my_string = "abcdefg"
if my_string.include? "cde"
puts "String includes 'cde'"
end`
Remember that include? is case sensetive. So if my_string in the example above would be something like "abcDefg" (with an uppercase D), include?("cde") would return false. You may want to do a downcase() before calling include?()
The other answers give absolutely the cleanest ways of checking your URL. I want to share a way of doing this using a regular expression so you can check your URL for a string at a particular location in the URL.
This method is useful when you have locales as first part of your URL like /en/users.
module MenuHelper
def is_in_begin_path(*url_parts)
url_parts.each do |url_part|
return true if request.path.match(/^\/\w{2}\/#{url_part}/).present?
end
false
end
end
This helper method picks out the part after the second slash if the first part contains 2 word characters as is the case if you use locales. Drop this in your ApplicationController to have it available anywhere.
Example:
is_in_begin_path('users', 'profile')
That matches /en/users/4, /en/profile, /nl/users/9/statistics, /nl/profile etc.