this should be simple, but I can't find the right variable.
I'm customizing a Freemarker template in struts2 (simple -> radioMap)
The structure of the template is basically :
<#s.iterator value="parameters.list">
//Display each item in the list
</#s.iterator>
What I'm trying to do, is display the number of each item in the iteration.
I need to get the index of each iterated item, so that I can print
0 - Item A
1 - Item B
....
How can I get such an index?
Thanks!
Since #s.iterator is not a standard FreeMarker directive, I don't know if it puts the current index into some variable or not (the standard directive #list does, but apparently they use their own iterator for some reason). However, you could just count yourself, like:
<#local idx = 0>
<#.iterator ...>
<#local idx = idx + 1>
...
</#.iterator>
Note that the usage of #local assumes that this "radioMap" thing is a macro. If it isn't, you had to use <#assign ...> instead, and then I hope this code is called in its own FreeMarker namespace (i.e., it's #import-ed, not #include-d) or in its own FreeMarker Environment, or else you can have name clashes.
The S2 iterator tag uses the status attribute to name the loop status variable.
The property tag can be used to retrieve the loop status variable.
http://struts.apache.org/2.x/docs/iterator.html
To use the native FM looping you can use the stack.findValue() method.
http://struts.apache.org/2.x/docs/freemarker.html
Related
I would like to redefine TCL's foreach, since multiple applications of foreach break some code.
Detailed problem description
The actual case where the code breaks happens in Vivado, a program using TCL for scripting. They supply an API that specifies get_<someObject> methods, which returns a list of objects (actually something that behaves like a list, but is implemented by xilinx to handle caching/printing a bit differently). To handle these lists I use foreach. The first time I use foreach on the list, I get <objects> in the loop variable.
However, if I apply foreach on a single object, the object is converted into a string representing its name. The problem is, that the API function get_property expects an object.
While applying foreach twice, does not seem to make sense, this might happen if you write two functions that take a list of objects and operate on them.
i.e.
proc a {obj} {
puts "logging [llength $obj] objects:"
foreach o $obj {
puts "$o has column index [get_property COLUMN_INDEX $o]"
}
}
proc b {obj} {
foreach o $obj {
a $o
puts "working on $o"
get_property COLUMN_INDEX $o
}
}
If we now call these functions as follows
a [get_clock_regions X0Y0] # ok (the list is turned into single objects in foreach)
b [get_clock_regions X0Y0] # crashes inside a (the list from get_clock_regions is
# turned into objects by the foreach in b
# a is then called with a single object,
# the foreach now turns the object into a string
# representing the name, but get_property
# does not work on strings => error
I asked if the behaviour can be fixed in this question on the Xilinx Forums, however I am looking for a workaround for the meantime.
What I am trying to do
I would like to implement a workaround for the meantime. While I can do
a [list $o]
inside b, I think it would be nicer if I can redefine foreach to not break the above case. This way, I can simply drop my redefinition of foreach if Xilinx can fix the behaviour. (I am expecting foreach to work the same regardless if I have a list with one element or a single element, to my understanding this is the same in TCL).
My issues with redefining foreach are:
How do I know if foreach is called as
foreach {varA varB} {valueList} {...}
foreach {varA varB} {valueList1 valueList2} {...}
Is there a way to test if I have an object or a list containing one object? The Idea is two detect if it is just an object, if so wrap it into a list, which then can be unwrapped back to object by the normal foreach, however I have no clue how to detect this case.
Outline code I would like to write:
proc safeForeach {varnames valueLists body} {
if { thereAreMultiple valueLists } { # this issue no 1
foreach valueList $valueLists {
if {wouldDecayToString $valueLists} { # this is issue no 2
set valueLists [list $valueLists]
}
}
} else {
if {wouldDecayToString $valueLists} { # this is issue no 2 again
set valueLists [list $valueLists]
}
}
#the next line should be wraped in `uplevel`
foreach $varnames $valueLists $body
}
The root cause of the problem is (using your example) invoking proc a, which expects a list, with only a single scalar value when it is called in proc b. Your "workaround" of invoking a as, a [list $o], is the solution. It converts a single value into a list of one element. A list containing one element is not the same as a single value. Since lists in Tcl are just specially formatted strings, if the argument to proc a contains whitespace it will be treated as a list, split up into the whitespace separated components. Although Tcl is flexible enough to allow you to radically redefine the language, I think this is a case of "just because you can, doesn't mean you should." I just don't think this case is compelling enough since some code refactoring would make the problem disappear.
Ultimately, the issue is that you don't want to treat simple values as lists. One of the ways of dealing with that is indeed to use [list $a] to make a list out of the value that shouldn't be mistreated, but another is to change the a procedure to take multiple arguments so that you can treat them as a list internally while having quoting automatically applied:
# The args argument variable is special
proc a {args} {
puts "logging [llength $args] objects:"
foreach o $args {
puts "$o has column index [get_property COLUMN_INDEX $o]"
}
}
Then you can call it like this:
a $o
When passing in a list to a procedure like this, you want to use expansion syntax:
a {*}[get_clock_regions X0Y0]
That leading {*} is a pseudo-operator in Tcl, which means to interpret the rest of the argument as a list and to pass the words in the list as their own arguments.
I'm new to Ruby and I'm having trouble understanding what's happening in this method.
I make this call in a Rails controller -
#arr = SomeClass.find_max_option(params[:x], #pos, params[:y], some_var)
I'm trying to return the value to #arr, which happens successfully, but manipulations I make to #pos within that method are being brought back as well; the value of #pos changes when I'm only trying to get the value for #arr.
Here's more details on the method
#before going into the method
#pos = [a,b]
def self.find_max_option(x, pos, y, some_var)
pos.collect! { |element|
(element == b) ? [c,d] : element
}
end
#new value of pos = [a, [c,d]] which is fine for inside in this method
... #some calculations not relevant to this question, but pos gets used to generate some_array
return some_array
But when the method is finished and gets back to the controller, the value of #pos is now [a,[c,d]] as well.
What's going on here? I thought that pos would be treated separately from #pos and the value wouldn't carry back. As a workaround I just created a new local variable within that method, but I'd like to know what this is happening
#my workaround is to not modify the pos variable
pos_groomed = pos.collect { |element|
(element == b) ? [c,d] : element
}
end
Instead of using collect!, just use collect (without the !). So, rewrite your method as:
def self.find_max_option(x, pos, y, some_var)
pos.collect { |element|
(element == b) ? [c,d] : element
}
end
When using the ! version of collect, you are replacing each element with the value returned by the block. However, when using collect without !, a new array is created, and the object where collect is being called it doesn't get changed. See the docs:
collect! vs collect
Using ! at the end of a method name is a common practice in Ruby. This question is related and would be worth taking a look.
You are using the destructive version of collect.
Destructive methods change the object on which the method is called, while non-destructive methods return new objects.
Ruby developers tend to call these methods 'bang methods', because the convention is that destructive methods have the ! suffix.
pos.collect! # changes pos and returns pos
pos.collect # creates a new object
Your workaround only works because you use the non-destructive collect, while the original code uses collect!
pos.collect do |element|
(element == b) ? [c,d] : element
end
Should work just fine.
As to why the object changes outside of the method:
In ruby, when you pass an argument to a method, you are actually passing the reference to the object.
So passing an array into a method doesn't make a copy, but simply passes the reference to original array.
There is no way to 'pass by value' but you can create a copy yourself with dup or clone, if you really have to.
Is there an easy way to get a default value from an Erlang record definition? Suppose I have something like this:
-record(specialfield, {
raw = <<"default">> :: string()
}).
I would like to have some way to retrieve the default value of the raw field. Something like this would be very simple:
#specialfield.raw % => <<"default">>
This is not possible. I would need to instantiate a record in order to get the default value:
Afield = #specialfield{}
DefaultValue = Afeild#specialfield.raw
DefaultValue % => <<"default">>
Is there an easier way of doing this? I seems like there should be some way to retrieve the default value without having to create an instance of the record.
How about:
raw_default() -> <<"default">>.
-record(specialfield, { raw = raw_default() }).
And now you have a function with the default in it. This will be extremely fast since it is a function call to a constant value. If this is also too slow, enable inlining.
Constructing an empty record and accessing one field can be done on one line:
(#specialfield{})#specialfield.raw.
Take a look at erlang - records, search section "11.8".
There's not much special about records - they're just a tuple at runtime. So to get the field raw from the tuple of default values that is the internal representation of #specialfield{} you would use:
element(#specialfield.raw, #specialfield{}).
In this case, #specialfield.raw is the index of the value for raw in the #specialfield tuple. When you pass in specialfield that resolves to a tuple in the form {specialfield, <<"default">>}.
The situation I have is that I'm querying MongoDB with a string for a field that is more than one level deep in the object hierarchy. This query must be a string. So for example I'm querying for something like this in Groovy:
def queryField = 'a.b.c' //this is variable and can be different every time
def result = mongodb.collection.findOne([queryField:5])
The problem no arises that in the result I want to find the value of the nested field. With GPath I could go one level deep and get a's value doing this
def aObj = result."a" //or result["a"]
However I want to go deeper than that by doing something like this:
def queryField = "a.b.c" //this can change every time and is not always 'a.b.c'
def cObj = result[queryField] //since field is variable, can't just assume result.a.b.c
This does not work in Groovy right now. There is a bug logged here, but I was wondering if there is a better work around to use for this scenario that is a bit cleaner than me parsing the string by splitting on the dot and then building the object traversal. Note that "a.b.c" is variable and unknown at runtime (e.g. it could be "a.b.d").
Based on the bug/thread it would appear there are some ambiguity problems with supporting a dotted property accessor. Based on the mailing list thread it would seem that evaluating the queryField string would be your best bet:
def result = [a: [b: [c: 42]]]
def queryString = 'a.b.c'
def evalResult = Eval.x(result, 'x.' + queryString)
assert evalResult == 42
Script on Groovy Web Console
The mailing list thread is a little old, so there's a new-ish (since at least 1.7.2) Eval class that can help out with running small snippets that don't have a large binding.
Otherwise, you can split the string and recursively do property evaluations on the object, effectively reproducing a subset of GPath traversal behavior.
I have a domain class that is just a list of strings (youtubeLinks).
When saving these links I want to strip out the video ID and save it instead of the entire URL entered on the UI side.
This is what I'm trying (ignore that the regex is flawed)
youtubeLinks.each {
def youtubeRegex = /v=(.*)/
def matcher = ( it =~ youtubeRegex )
it = matcher[0][1]
}
When I save this, it saves the original value of "it". Is there a way to update this reference and have it save properly?
Thanks.
Groovy's each loop is merely an iterator, and as such it neither affects the collection on which it operates, nor returns a value of its own. It's basically equivalent to Java's "advanced for loop (for-each)," only with the convenience of dynamic typing and an implicit loop variable (it). While it can be modified, it's a futile enterprise, as you'd be simply changing a reference to the original value, not the value itself. See this question for more on that.
When you need to modify every element within a collection somehow, the idiomatic Groovy (Grails) solution is to use the collect method. Collect transforms each element via the closure you provide, ultimately returning a new collection ( so, it doesn't actually "modify" anything).
Basically, you'll probably want to do something like this:
def links = '''http://www.youtube.com/watch?v=fl6s1x9j4QQ
http://www.youtube.com/watch?v=tCvMKcNJCAY
'''
assert (links =~ /watch\?v=(.*)/).collect{match -> match[1]} == ["fl6s1x9j4QQ", "tCvMKcNJCAY"]
..Though there are actually a number of ways one could go about such a task in Groovy.
Additionally, Ted Naleid's blog has some nice examples of Groovy pattern matching that you may find useful.
Edit
Here are several ways in which you could abbreviate the solution you submitted:
youtubeLinks = youtubeLinks.collect{link -> (link =~ /\?v=(.*)$/)[0][1]}
or
youtubeLinks = youtubeLinks.collect{link -> link.replaceAll(/^.*\?v=/, "") }
or this (Though it's a little contrived)
youtubeLinks = youtubeLinks.join('\n').replaceAll(/.*\?v=/, '').split()
You were right, it ended up being like
youtubeLinks = youtubeLinks.collect {
def youtubeRegex = /v=(.*)[&]/
def matcher = ( it =~ youtubeRegex )
return matcher[0][1]
}
Thanks, Northover.