How do I set a dynamic node attribute based on a condition in groovy when using the NodeBuilder pattern?
Like the following
def b = DOMBuilder.newInstance()
b.div ( attribute: "value") {
if (condition) {
// Set div.dynamicAttribute to true here
}
}
Preferably it would be nice to reference the current element in the conditional statement since the condition might appear deep down in the structure.
The easiest way to do this is to evaluate the condition for the dynamic attribute outside the node closure. For Example:
if (condition) {
b.div(attribute: "value", dynamicAttribute: true) {
...
}
} else {
b.div(attribute: "value") {
...
}
}
Alternatively, you can create a map of the attributes beforehand:
def attributes = [attribute: "value"]
if (condition) {
attributes['dynamicAttribute'] = true
}
b.div(attributes) {
...
}
Related
I have a Core Data NSManagedObject entity Person with a Bool attribute that I generate as a NSNumber. (the "Use Scalar Type" checkbox is not used, so the Bool attribute becomes an NSNumber)
I am trying to observe this attribute, employed, to control the UI.
#ObservedObject var person: Person
var body: some View {
List {
Section {
HStack {
Toggle(isOn: $person.employed) { <-- 1
Text("Showing employed content..")
}
}
}
if person.employed.boolValue {
Section { } etc
I get a warning at "1" saying: Cannot convert value of type 'Binding<NSNumber?>' to expected argument type 'Binding<Bool>'
How can I make use of the employed attribute as a bool without changing it to a scalar?
Note: $person.employed.boolValue would not work it seems, and I would also have to account for the optional part.
One possible way to do it is via a custom Binding:
Toggle("Showing employed content..", isOn: Binding<Bool>(get: {
person.employed?.boolValue == true
}, set: { value in
person.employed = NSNumber(value: value)
}))
Now, if you prefer this to be a computed property instead, you could do something like this:
var isEmployed: Binding<Bool> {
Binding<Bool>(get: {
person.employed?.boolValue == true
}, set: { value in
person.employed = NSNumber(value: value)
})
}
var body: some View {
Toggle("Showing employed content..", isOn: isEmployed)
}
Also, here is a possible implementation of an extension that handles optional NSNumber backed booleans (excuse my terible naming):
extension Binding where Value == NSNumber? {
var boolBinding: Binding<Bool> {
Binding<Bool>(get: {
self.wrappedValue == true
}, set: { value in
self.wrappedValue = NSNumber(value: value)
})
}
}
which can be used like this:
Toggle("Showing employed content..", isOn: $person.employed.boolBinding)
I wonder howto access an object's attribute dynamically via a name as a Str at runtime in Raku. Instead of:
#!/usr/bin/rakudo
class c0 {
has $!a0 = 1;
has $!a1 = 2;
method access(Str $m) {
if ($m eq "a0") { return $!a0; }
if ($m eq "a1") { return $!a1; }
}
method set(Str $m, $v) {
if ($m eq "a0") { $!a0 = $v; }
if ($m eq "a1") { $!a1 = $v; }
}
}
my $c = c0.new();
$c.set("a0", 3);
$c.set("a1", 4);
say $c.access("a0");
say $c.access("a1");
I would like to use something that would look in pseudocode:
class c0 {
...
method access(Str $m) {
return self.$m;
}
method set(Str $m, $v) {
self.$m = $v;
}
}
Is this possible in Raku? Which construct do I need to use?
As a backgrounder I was thinking how to implement a role that adds associativity functionality to the class, to transparently access a member. The attribute name would be parametrized: If I have a class class ports { has #!ports_; ... } and an instance my $p = ports.new() then I want to be able to use the subscript syntax to access #ports_ via $p[...] . I try to figure out weather I can define role acc [ Str $member] does Associative[Cool,Str] { ... } and then define ports via class ports does acc["ports_"] { ... }
where the AT-KEY and EXISTS-KEY in role acc are implemented using dynamic attribute access (if that is possible).
I dont want to use "EVAL".
This is possible with some introspection of the attributes. However, I would like to point out that it is the exact intention of private attributes to be private. Creating a workaround to handle them as public attributes is an anti-pattern, and introduces needless complexity.
class c0 {
has $.a0 = 1;
has $.a1 = 2;
method access (Str $m) {
my $attribute = self.^attributes.first({ ~$_ eq '$!' ~ $m });
return unless $attribute;
$attribute.get_value(self); # 1
}
}
my $c = c0.new;
say $c.access('a0');
For setting the value, you can use the .set_value method on the attribute.
method set (Str $m, $v) {
...
$attribute.set_value(self, $v);
}
Old answer left here for historic purposes.
Yes, something like this is possible in Raku. You don't even need to explicitly define the access method.
class c0 {
has $.a0 = 1;
has $a.1 = 2;
}
my $c = $c0.new;
say $c.'a0'(); # 1
This works because Raku creates an accessor method for public variables for your classes, which is called when you use .'a0'(). The () are required for using a quoted method name.
You changed your post to add a question about how to do something like this:
role acc [ Str $member] does Associative[Cool,Str] { ... }
class ports does acc["ports_"] { has #!ports_; ... }
The answer is of course, don't do that.
I mean you can, but you really shouldn't.
I mean you really really shouldn't.
Also you indicate that you want to use [] for indexing.
The thing is that is Positional not Associative.
(I'm ignoring the fact that there is no point to add _ to the end of the attribute name. Usually in Perl or Python adding _ indicated private, but we don't need to do that in Raku.)
The right way to do that is to have the array inside of the role.
role Array::Access [::OF = Cool] does Positional[OF] {
has OF #!array-access handles < AT-POS >;
}
class Ports does Array::Access {
# allows you to access it as self!ports inside of this class
method !ports () is raw { #!array-access }
}
Which shows that adding a role to do that is probably overkill.
class Ports does Positional[Cool] {
has Cool #!ports handles < AT-POS >;
}
If you really, really want to do it they way you asked for, the following works.
role Inner::Array::Access [ Str:D \name, ::OF = Cool ] does Positional[OF] {
# a way to quickly access the attribute
# (hopefully no-one tries to add an attribute of this name to their class)
has $!inner-array handles < AT-POS >;
# set $!inner-array
submethod TWEAK (){
$!inner-array := self.^attributes.first(name).get_value(self);
}
}
class Ports does Inner::Array::Access['#!ports'] {
has #!ports;
# a quick way to add a way to set #!ports for our test
submethod BUILD( :#!ports ){}
}
my Ports $v = ports => [0,10,20,30];
say $v[2]; # 20
Probably what you were thinking is embed the self.^attributes thing into AT-POS.
role Inner::Array::Access [ Str:D \name, ::OF = Cool ] does Positional[OF] {
method AT-POS ( \index ) is raw {
self.^attributes.first(name).get_value(self).AT-POS(index);
}
}
That would be slow, because it has to do all of those lookups everytime you access a single element.
I'm developing a Jenkins shared library right now.
I wasn't able to figure how to easily "wrap" a code inside a function without copy-pasting the whole code. For example: If a developer sets a value to true, then I want to wrap the whole code inside a function. Right now I want to use this to allow e.g. the gitlabIntegration to be turned off from the Jenkinsfile.
Example:
// vars/stageWrapper.groovy
def call(Map parameters = [:], body) {
stage(stageName) {
if (pushtoGitlab) {
gitlabCommitStatus(stageName) {
if (!containerName) body()
else {
container(containerName) {
body()
}
}
}
} else {
if (!containerName) body()
else {
container(containerName) {
body()
}
}
}
}
}
let the user select if the stage should be pushed to gitlab via the gitlabCommitStatus wrapper.
switch to a specified container or use default container (if none is specified)
To realize this I currently repeat the code, which I really don't like...
Is there any way of achieving the same, but without repeating the same code over and over?
Thank You!
In Groovy you can reuse a Closure in different DSL-Builders by setting it's delegate to builder's delegate.
Something like this should work:
def containerNameBody = { body ->
if (!containerName)
body()
else
container(containerName) {
body()
}
}
def call(Map parameters = [:], body) {
stage(stageName) {
containerNameBody.delegate = delegate
if (pushtoGitlab)
gitlabCommitStatus(stageName) {
containerNameBody body
}
else
containerNameBody body
}
}
How about following approach to pass down the param into function, then decide how to do inside the function by the param value.
def gitHub(gitHubOn) {
}
def gitLab(gitLabOn) {
}
def call(Map parameters = [:], body){
//some code....
foo=bar
gitLab(parameters.gitLabOn)
gitHub(parameters.gitHubOn)
body()
}
I know how to check a string is in another string
like this code.
when (myString) {
in "FirstString" -> {
// some stuff
}
in "SecondString" -> {
// some stuff
}
else -> {
// some stuff
}
}
in keyword under the hood calls this method CharSequence.contains(other: CharSequence, ignoreCase: Boolean = false)
the question is this :
is there any way that in this case i can set ignoreCase = true ?
You can declare an ad-hoc local operator function contains for strings before when:
fun main() {
operator fun String.contains(other: String): Boolean = this.contains(other, ignoreCase = true)
when(myString) {
in "firstString" -> ...
}
}
This way that function will be invoked for in operator instead of the one declared in the standard library because it's located in the closer scope.
Note, however, that this trick works only if the original contains function is an extension. If it's a member function, it cannot be overridden with an extension.
You can use toLowerCase() function here :
when (myString.toLowerCase()) {
in "firststring" -> {
// some stuff
}
in "secondstring" -> {
// some stuff
}
else -> {
// some stuff
}
}
For the cases of when, if they're variables toLowerCase() needs to be called on each of them. But, if they're constants, simple using lower case strings will work - "firststring", "secondstring"
My Problem
Consider a nested object:
> { a: { b: { c: 3 } } }
{ a: { b: { c: 3 } } }
Accessing an inner property with a dot notation for fixed values is done using a dot notation:
> x.a.b.c
3
I would like to access an arbitrary property depending on some condition, for example, instead of accessing b I would like to access the property who's name is stored in the SOME_VARIABLE variable:
> x.a.{SOME_VARIABLE}.c
3
What have I tried
STFW. Probably don't know the exact terminology.
My question
How can I refer to an object property dynamically, with a property name defined in a variable?
There are multiple ways to access an object one of them being [] instead of dots if a object is var object = { inside : '1' } you can access it like this object['inside']. Remember to pass quotes inside if it's static and if it's dynamic pass the variable
I've added an example below
var a = { b: { c: 1 } };
var d = 'b';
console.log(a[d]['c']);
You might also consider using a library like lodash which provides functions to "reach inside" a complex object and return a value, of if the path doesn't exist, a default value.
Example:
const _ = require('lodash')
const target = {
foo: {
bar: {
baz: [1, 2, 3]
}
}
}
console.log(_.get(target, 'foo.bar.baz.1')) // ==> 2
console.log(_.get(target, 'foo.3.bar', 'DEFAULT')) // ==> DEFAULT
if (_.has(target, 'foo.bar')) {
// do something interesting
}
const newKey = 'blorg'
_.put(target, `foo.bar.${newKey}`, 'hello?')
/*
target is now {
foo: {
bar: {
baz: [1, 2, 3]
},
blorg: 'hello?'
}
}
*/