get calling function with more hierarchical depth - scala-2.10

The following code gets the calling function (like C _ _ FUNC _ _):
def __func__(c: Context) = {
import c.universe._
c.enclosingMethod match {
case DefDef(mods, name, tparams, vparamss, tpt, rhs) =>
c.universe.reify(println(
"\n mods "+c.literal(mods.toString).splice
+"\n name "+c.literal(name.toString).splice
+"\n tparams "+c.literal(tparams.toString).splice
+"\n vparamss "+c.literal(vparamss.toString).splice
+"\n tpt "+c.literal(tpt.toString).splice
+"\n rhs "+c.literal(rhs.toString).splice
))
case _ => c.abort(c.enclosingPosition, "NoEnclosingMethod")
}
}
But how to get more depth i.e. get the name of the function calling the function calling the macro?
Thanks in advance for yoiur help.

You could try inspecting c.enclosingUnit or something simpler like c.enclosingClass or c.enclosingMethod. After getting the enclosure you could traverse it and try to detect the parents of your c.macroApplication.
However this approach would probably be not very robust, because the typechecker can significantly rehash the trees being typechecked, so you won't be able to find post-typer c.macroApplication in pre-typer enclosing trees. I remember someone having these problems, but I haven't tried this approach myself.

Related

How to create a filter on an aws glue dynamicframe that filters out set of (literal) values

In a glue script (running in a zeppelin notebook forwarding to a dev endpoint in glue), I've created a dynamicframe from a glue table, that I would like to filter on field "name" not being in a static list of values, i.e. ("a","b","c").
Filtering on non-equality works just fine like this:
def unknownNameFilter(rec: DynamicRecord): Boolean = {
rec.getField("name").exists(_ != "a")
}
I have tried several things like
!rec.getField("name").exists(_ isin ("a","b","c"))
but it gives errors (value isin is not a member of Any), and I can only find pyspark examples and examples that first convert the dynamicframe to a dataframe on the web (which I want to prevent if possible).
Help much appreciated, thanks.
Okay, found my answer, I'll post it for anyone else looking for this, it is done with
!(knownevents.contains(eventname))
Like this in a filter function:
def unknownEventFilter(rec: DynamicRecord): Boolean = {
val knownevents = List("evt_a","evt_b")
rec.getField("name") match {
case Some(eventname: String) => !(knownevents.contains(eventname))
case _ => throw new IllegalArgumentException(s"Unable to extract field name")
}
}
val dfUnknownEvents = df.filter(unknownEventFilter)

DBArrayList to List<Map> Conversion after Query

Currently, I have a SQL query that returns information to me in a DBArrayList.
It returns data in this format : [{id=2kjhjlkerjlkdsf324523}]
For the next step, I need it to be in a List<Map> format without the id: [2kjhjlkerjlkdsf324523]
The Datatypes being used are DBArrayList, and List.
If it helps any, the next step is a function to collect the list and then to replace all single quotes if any [SQL-Injection prevention]. Using:
listMap = listMap.collect() { "'" + Util.removeSingleQuotes(it) + "'" }
public static String removeSingleQuotes(s) {
return s ? s.replaceAll(/'"/, '') : s
}
I spent this morning working on it, and I found out that I needed to actually collect the DBArrayList like this:
listMap = dbArrayList.collect { it.getAt('id')}
If you're in a bind like I was and restrained to a specific schema this might help, but #ou_ryperd has the correct answer!
While using a DBArrayList is not wrong, Groovy's idiom is to use the db result as a collection. I would suggest you use it that way directly from the db:
Map myMap = [:]
dbhandle.eachRow("select fieldSomeID, fieldSomeVal from yourTable;") { row ->
map[row.fieldSomeID] = row.fieldSomeVal.replaceAll(/'"/, '')
}

How to check if a TypedPipe or a ValuePipe are empty in Scalding?

In Scalding, suppose you have a TypedPipe[Long] or ValuePipe[Long]. How would you go about checking whether they are empty in the most elegant/efficient way?
Currently testing the following:
val isTPEmpty: Boolean = typePipe.equals(TypedPipe.empty)
val isVPEmpty: Boolean = valuePipe.equals(EmptyValue)
Or, to make it more generic:
def isTypedPipeEmpty[A](typedPipe: TypedPipe[A]): Boolean = {
val emptyTP: TypedPipe[A] = TypedPipe.empty
typedPipe.equals(emptyTP)
}
UPDATE: this doesn't work (will return false for an empty TypedPipe). Appreciate any inputs.
After speaking to several people on this, there is no straight solution simply because a TypedPipe is distributed, and checking whether it is empty is "expensive", therefore one should avoid this as much as possible.
If you absolutely have no choice, what worked for me was something "ugly" as creating a temporary empty TypedPipe, then calling mapWithValue on my ValuePipe, and if it is empty do X, otherwise do Y. Something like:
TypedPipe.from(List()).mapWithValue(valuePipe) { case (temp, valuePipe) => if (valuePipe.isEmpty) doX else doY }
But again, cumbersome.

In VTD-XML how to add new attribute into tag with existing attributes?

I'm using VTD-XML to update XML files. In this I am trying to get a flexible way of maintaining attributes on an element. So if my original element is:
<MyElement name="myName" existattr="orig" />
I'd like to be able to update it to this:
<MyElement name="myName" existattr="new" newattr="newValue" />
I'm using a Map to manage the attribute/value pairs in my code and when I update the XML I'm doing something like the following:
private XMLModifier xm = new XMLModifier();
xm.bind(vn);
for (String key : attr.keySet()) {
int i = vn.getAttrVal(key);
if (i!=-1) {
xm.updateToken(i, attr.get(key));
} else {
xm.insertAttribute(key+"='"+attr.get(key)+"'");
}
}
vn = xm.outputAndReparse();
This works for updating existing attributes, however when the attribute doesn't already exist, it hits the insert (insertAttribute) and I get "ModifyException"
com.ximpleware.ModifyException: There can be only one insert per offset
at com.ximpleware.XMLModifier.insertBytesAt(XMLModifier.java:341)
at com.ximpleware.XMLModifier.insertAttribute(XMLModifier.java:1833)
My guess is that as I'm not manipulating the offset directly this might be expected. However I can see no function to insert an an attribute at a position in the element (at end).
My suspicion is that I will need to do it at the "offset" level using something like xm.insertBytesAt(int offset, byte[] content) - as this is an area I have needed to get into yet is there a way to calculate the offset at which I can insert (just before the end of the tag)?
Of course I may be mis-using VTD in some way here - if there is a better way of achieving this then happy to be directed.
Thanks
That's an interesting limitation of the API I hadn't encountered yet. It would be great if vtd-xml-author could elaborate on technical details and why this limitation exists.
As a solution to your problem, a simple approach would be to accumulate your key-value pairs to be inserted as a String, and then to insert them in a single call after your for loop has terminated.
I've tested that this works as per your code:
private XMLModifier xm_ = new XMLModifier();
xm.bind(vn);
String insertedAttributes = "";
for (String key : attr.keySet()) {
int i = vn.getAttrVal(key);
if (i!=-1) {
xm.updateToken(i, attr.get(key));
} else {
// Store the key-values to be inserted as attributes
insertedAttributes += " " + key + "='" + attr.get(key) + "'";
}
}
if (!insertedAttributes.equals("")) {
// Insert attributes only once
xm.insertAttribute(insertedAttributes);
}
This will also work if you need to update the attributes of multiple elements, simply nest the above code in while(autoPilot.evalXPath() != -1) and be sure to set insertedAttributes = ""; at the end of each while loop.
Hope this helps.

How do you read a variable from another variable

Horse_Apple = "Happy Horse"
local var = Animal() .. "_" .. Food()
print(var)
I hope someone here understands the problem i'm trying to solve here. Animal() returns "Horse" and Food() returns "Apple".
What i'm attempting to do is read the variable 'var' and read its value 'Horse_Apple' as a variable which should return "Happy Horse". As much as im trying to find the solution to this im failing big time, Thank you.
You can access a global variable by a dynamic name using _G, i.e.:
print(_G[var])
Normally this isn't considered good design: It's better to make Horse_Apple a key in some table and access that table instead, like this:
values = { Horse_Apple="Happy Horse" }
local var = Animal() .. "_" .. Food()
print values[var]