Groovy Templates - Non Standard Parameters, with minus signs - templates

I'm trying to render a map that has keys containing minus signs (e.g. first-name). Here is an exemplary template I'm trying to render:
String text = "Dear \"$first-name $lastname\",\nSo nice to meet you";
When I render it with Groovy template engine (can be either SimpleTemplateEngine or MarkupTemplateEngine) it complains and throws an exception. When I remove the '-' from the variable name, it works OK.
Is there anyway to escape these variables in the Groovy template text?
BTW - the reason I'm doing it this way is to render a JSON blob from a 3rd party API.

There is at least one way to do it. It doesn't work in your case for the same reasons you can't use - character in variable name. When you define an expression like:
${first-name}
Groovy sees it as:
${first.minus(name)}
and that is why it throws exception like:
Caught: groovy.lang.MissingPropertyException: No such property: first for class: SimpleTemplateScript1
groovy.lang.MissingPropertyException: No such property: first for class: SimpleTemplateScript1
at SimpleTemplateScript1.run(SimpleTemplateScript1.groovy:1)
You can keep keys like first-name in your bindings, but you would have to put them in a map, so you can access first-name value using Map.get(key) function. Consider following example:
import groovy.text.SimpleTemplateEngine
def engine = new SimpleTemplateEngine()
def bindings = [
'first-name': 'Test',
'lastname': 'qwe'
]
String text = 'Dear "${map["first-name"]} ${map["lastname"]}",\nSo nice to meet you'
println engine.createTemplate(text).make([map: bindings])
In this example I put bindings into a map with a key map. When I do so I can access my bindings as map['first-name'] and map['lastname']. Running this example produces expected output:
Dear "Test qwe",
So nice to meet you
Hope it helps.

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.

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.

How can i make argparse suparser match any string?

i am using
parser = argparse.ArgumentParser()
subparser = parser.add_subparsers()
add_parser = subparsers.add_parser("add", help="Add parser")
add_parser.add_argument("-project", default="global")
edit_parser = subparsers.add_parser("edit", help="Edit parser")
I want to achieve smething like this:
python myprogram.py add
python myprogram.py edit
python myprogram.py "A random string"
Where in the first two usecases my program can asign the right subparser based on the keyword "add" or "edit". I am interested in the last case, where it maps to any random string that i provide.
There isn't a direct way of doing this. The use of subparsers is an extension of a positional argument with choices.
parser.add_argument('cmd', choices=['add', 'edit', ...])
It accepts a string if it is in choices. There isn't a builtin pattern matching mechanism.
I think your simplest solution would be to add one step:
custom = subparser.add_parser('custom', help='give a random string')
custom.add_argument('anystring', help='random quoted string')
python myprogram.py custom 'any random string'
I can imagine writing a custom choices class that could do both kinds of matching. It would require a custom __contains__ method (and maybe a new __iter__ to list choices in the help). But incorporating that into the _SubParsersAction class would require some serious coding.
A few more details. Your subparser object is an _SubParsersAction. Its choices attribute is an OrderedDict. When you add_parser, it creates a new ArgumentParser (the add_parser object), and enters it into the dict with the named key (plus any aliases). When parsing your input, argparse matches the strings against the keys of this dictionary. So, to implement your ideal, you'd have to change this dictionary lookup.
Another option is to look at sys.argv[1:] at the start. If one of your 'cmds' is present call the parser to get the full subparser action. Otherwise handle the inputs yourself, or call another parser that handles 'a random string' as an ordinary positional argument. Sometimes it just isn't worth the effort to twist argparse into a special shape.

Custom regex validation in Play Framework - Scala

I am new to Play 2.3.x and Scala and trying to implement a form input validation.
Let us say I have an example form.
val userForm = Form(
"firstName" -> nonEmptyText
)
I want to implement something like this for the first name field:
If a regex for first name (say firstName.regex = “regex for first name” ) is defined then {
Validate first name against specific regex
}else{
Validate against the global regex ( say global.regex = “global regex white list some regex valid for across the application”)
}
Also, I want to combine this with multiple (chained/step wise) validations so as to be able to display :
If nothing is entered - Please First name
If first name is enetred and fails regex validation - Please enter a valid first name
I want to develop a generic solution so that I can use it for all the fields.
Appreciate any help.
You can use verifying.
val userForm = Form(
"firstName" -> nonEmptyText.verifying("Must contain letters and spaces only.", name => name.isEmpty || name.matches("[A-z\\s]+") )
)
There's a little extra logic there (name.isEmpty with OR), because an empty string would trigger both validation errors. It seems like the validation errors are kept in order in which they're triggered, so you might be able to get away with using the first validation error in the sequence, but don't hold me to that. You can chain as many verifyings together as you like.
I'm not entirely sure what you have in mind by making these more generic, but you can make your own Mapping validators by composing already existing ones in the Forms object.
val nonEmptyAlphaText: Mapping[String] = nonEmptyText.verifying("Must contain letters and spaces only.", name => name.matches("[A-z\\s]+") )
And then you can use it in the Form:
val userForm = Form(
"firstName" -> nonEmptyAlphaText
)

In Django, how do I deal with an "or" in the url regex once I get to the view?

I'm just learning Django, and am getting stuck with some url logic. I'm trying to allow either a category name or id in the url:
...
url(r'^(?P<booze_q>\w+|\d+)/$','glasses.views.booze'),
...
And then in thew view, only deal with that result once. However, if the url is a string - in this case, Whiskey, I get an error for trying to pass a string where an int is expected. This is the closest I've gotten so far:
def booze(request, booze_q):
booze = get_object_or_404(Booze,Q(pk=booze_q)|Q(name=booze_q))
return render_to_response('booze/detail.html', {'booze': booze})
But this returns an error: invalid literal for int() with base 10: 'Whiskey'
I'm sure it's a pretty easy thing, but this is my first Django app, so any help would be appreciated.
tl;dr: End result, I'd like mysite.com/1/ or mysite.com/Whiskey/ to both call the glasses.views.booze view, and get the object with id=1 or name=Whiskey
This is a common scenario you'll encounter quite often, which is typically handled by resorting to multiple arguments and having views behave differently based on which of the view arguments are then present or not.
What you do is first define a URL pattern that uniquely matches each specific case and then let Django's URL resolver set the arguments accordingly based on which of the patterns was matched.
Here's an example with a class based view, that performs two different queries based on which of the two keyword arguments, booze_id or booze_name, is set:
url(r'^(?P<booze_id>\d+)/$', BoozeDetailView.as_view()),
url(r'^(?P<booze_name>\w+)/$', BoozeDetailView.as_view()),
class BoozeDetailView(DetailView):
model = Booze
def get_object(self):
booze_id = self.kwargs.get('booze_id', None)
booze_name = self.kwargs.get('booze_name', None)
if booze_id:
return self.model.objects.get(id=booze_id)
else:
return self.model.objects.get(name=booze_name)
You will always get a string, even if the string contains a number.
1) You should not have a parameter that could be either an id or something else. One day you will enter an item whose name is a number and your app will fail.
2) When querying for pk with a string django automatically tries to convert it into an integer. You'll have to handle the non-pk case before constructing that query.