Yang model mandatory node only when condition is true - ietf-netmod-yang

I have an XML file:
<a>
<b>true</b>
<c>foo</c>
</a>
and a Yang model:
container a {
leaf b {
type boolean;
}
leaf c {
type string;
}
}
Node 'c' is mandatory only when node 'b' equals 'true'. If I add a mandatory: true constraint to node 'c' it will become mandatory for all values of 'b'.
How to change the Yang model so that node 'c' is mandatory when 'b' is 'true' and optional when 'b' is false?

You can use the must statement with an XPath condition:
container a {
must 'not(b) or boolean(c)'
leaf b {
type boolean;
}
leaf c {
type string;
}
}

Yang1.1 support optional mandatory
container a {
leaf b {
type boolean;
}
leaf c {
when "../b";
mandatory true;
type string;
}
}

Related

Is there a shorthand boolean check for an enum case with associated value?

I have this code snippet:
if case .voice = mode {
return true
} else {
return false
}
Is there a shorthand version maybe? For example:
.voice == mode ? true : false
mode is an enum with associated value:
enum Mode {
case `default`
case voice(VoiceMode)
}
There is no built-in method for checking enum case equality without also checking the equality of the associated values. In case your enum conforms to Equatable, you can use the equality operator to compare two enum values, however, you still couldn't do mode == Mode.voice, since Mode.voice isn't valid without a VoiceMode associated value.
You can define a computed property on the enum that only compares the cases though, not their associated values.
enum Mode {
case `default`
case voice(VoiceMode)
var isVoice: Bool {
if case .voice = self {
return true
} else {
return false
}
}
}

Swift define and call inline closure directly

I can assign an inline closure to a function type
> var a = { ()-> Bool in return true }
and use it:
> true==a()
$R2: Bool = true
if the function is a throw-away, it would be nice to use an inline directly. This doesn't work:
> true=={ ()-> Bool in return true }
error: repl.swift:16:5: error: binary operator '==' cannot be applied to operands of type 'Bool' and '() -> Bool'
According to the error, the RHS is the inline's function type, not its return type. Is there a different syntax I should use? Is it possible to call an inline directly?
Edit, after answer: This comes in very handy in cascaded conditions in if statements: if b==2, { /* do something only if b==2 passes*/}(), let x = ... { ...} else {...}
> true == a()
compares true with the result of calling the closure a (with an empty argument list). You can do the same inline, but you must still call the closure:
> true == { ()-> Bool in return true }()
$R0: Bool = true
Note that a test for equality with true is always redundant, so this expression is identical to
{ ()-> Bool in return true }()

Comparison based default value for a leaf in a same list in yang model

I would like to assign different default value to a leaf according to type of key the list entries take. as an example, although not correct:
typedef type-id {
type enumeration {
enum a{
value 1;
}
enum b{
value 2;
}
enum c{
value 3;
}
}
}
list domain {
key id;
leaf id {
type type-id;
}
leaf my-leaf {
when "../id = 'a'"{
default 10;
}
when "../id = 'b'"{
default 20;
}
when "../id = 'c'"{
default 20;
}
}
}
So let say there are two entries for the list and the corresponding keys are 'a' and 'c'
When I walk through the model I would like to have values as
domain id my-leaf
'a' 10
'c' 30
Which expression is the best solution for this purpose? How can I model such a structure?

Declare dynamically added class properties in TypeScript

I want to assign properties to the instance of a class without knowing the property names, values and types of values in TypeScript. Lets assume we have the following example.ts script:
// This could be a server response and could look totally diffent another time...
const someJson:string = '{ "foo": "bar", "bar": "baz" }'
class MyClass {
someProperty:boolean
constructor( json:string ) {
const parsedJson:any = JSON.parse( json )
Object.keys( parsedJson ).forEach(
( key:string ) => {
this[ key ] = parsedJson[ key ]
}
)
this['someProperty'] = true
}
}
const myInstance = new MyClass( someJson )
// Works fine, logs `true`.
console.log( myInstance.someProperty )
// Error: Property 'foo' does not exist on type 'MyClass'.
console.log( myInstance.foo )
// Error: Property 'bar' does not exist on type 'MyClass'.
console.log( myInstance.bar )
How can I make sure that the TypeScript compiler does not complain of the dynamically added properties but instead handle them as "key": value pairs of any type. I still want tsc to make sure that myInstance.someProperty has to be of type boolean but I want to be able to get myInstance.whatever even if it is not defined without running into compiler errors.
I did not find any documentation that makes this clear to me. Maybe because I'm not a native english speaker. So please keep the answers simple.
Edit:
I remember that there was something like the following but I never got that to work:
interface IMyClass {
[name:string]: any
}
The problem is that you're adding the new properties at runtime and the compiler has no way of knowing that.
If you know the property names in advance then you can do this:
type Json = {
foo: string;
bar: string;
}
...
const myInstance = new MyClass(someJson) as MyClass & Json;
console.log(myInstance.foo) // no error
Edit
If you do not know the properties in advance then you can't do this:
console.log(myInstance.foo);
Because then you know that foo is part of the received json, you'll probably have something like:
let key = getKeySomehow();
console.log(myInstance[key]);
And this should work without an error from the compiler, the only problem with that is that the compiler doesn't know the type for the returned value, and it will be any.
So you can do this:
const myInstance = new MyClass(someJson) as MyClass & { [key: string]: string };
let foo = myInstance["foo"]; // type of foo is string
let someProperty = myInstance["someProperty"]; // type of someProperty is boolean
2nd edit
As you do know the props, but not in the class, you can do:
type ExtendedProperties<T> = { [P in keyof T]: T[P] };
function MyClassFactory<T>(json: string): MyClass & ExtendedProperties<T> {
return new MyClass(json) as MyClass & ExtendedProperties<T>;
}
Then you simply use it like so:
type Json = {
foo: string;
bar: string;
};
const myInstance = MyClassFactory<Json>(someJson);
Note that this will work only on typescript 2.1 and above.
If you want to dynamically add class properties via an object upon instantiation, and type information is available for that object, you can very nicely get full type safety in this way (as long as you don't mind using a static factory method):
class Augmentable {
constructor(augment: any = {}) {
Object.assign(this, augment)
}
static create<T extends typeof Augmentable, U>(this: T, augment?: U) {
return new this(augment) as InstanceType<T> & U
}
}
This is using the (fake) this parameter to infer the constructor type of the class. It then constructs the instance, and casts it to a union of the instance type (using the InstanceType utility type) and the inferred type of the props you passed to the method.
(We could have casted directly to Augmentable & U, however this way allows us to extend the class.)
Examples
Augment basic properties:
const hasIdProp = Augmentable.create({ id: 123 })
hasIdProp.id // number
Augment with methods:
const withAddedMethod = Augmentable.create({
sayHello() {
return 'Hello World!'
}
})
withAddedMethod.sayHello() // Properly typed, with signature and return value
Extend and augment, with this access in method augments:
class Bob extends Augmentable {
name = 'Bob'
override = 'Set from class definition'
checkOverrideFromDefinition() {
return this.override
}
}
interface BobAugment {
whatToSay: string
override: string
sayHelloTo(to: string): void
checkOverrideFromAugment(): string
}
const bobAugment: BobAugment = {
whatToSay: 'hello',
override: 'Set from augment'
sayHelloTo(this: Bob & BobAugment, to: string) {
// Let's combine a class parameter, augment parameter, and a function parameter!
return `${this.name} says '${this.whatToSay}' to ${to}!`
},
checkOverrideFromAugment(this: Bob & BobAugment) {
return this.override
}
}
const bob = Bob.create(bobAugment) // Typed as Bob & BobAugment
bob.sayHelloTo('Alice') // "Bob says 'hello' to Alice!"
// Since extended class constructors always run after parent constructors,
// you cannot override a class-set parameter with an augment, no matter
// from where you are checking it.
bob.checkOverrideFromAugment() // "Set from class definition"
bob.checkOverrideFromDefinition() // "Set from class definition"
Limitations
Augmented properties aren't really part of the class, so you can't extend a class with those augments included. This may be a feature for some use cases where the augments are temporary additions that aren't meant to modify the prototype hierarchy
It is also not easy to add non-augment arguments to .create(), however an easy work-around is to simply utilize the augment functionality to accomplish the same thing you would have with an extra argument.
You can add index signature to your class:
class MyClass {
[index: string]: any; //index signature
someProperty:boolean
constructor( json:string ) {
const parsedJson:any = JSON.parse( json )
Object.keys( parsedJson ).forEach(
( key:string ) => {
this[ key ] = parsedJson[ key ]
}
)
this['someProperty'] = true
}
}

Explicitly specify an associated type

In the following example, my 'Type' has an 'Option'. And I use them in a Field struct by insuring that they are coherent thanks to the where clause in the Generics part.
protocol Type {
associatedtype O: Option
var typeOption: O? { get }
}
protocol Option {
}
struct Field<T: Type, O: Option where T.O == O> {
let type: T
let option: O
}
It works fine. But the typeOption property is useless. In fact I put it only so the type of the Option can be inferred as with the String's extension example.
struct StringOption: Option {
}
extension String: Type {
var typeOption: StringOption? {
return nil
}
}
So my question is, can I get rid of this useless property or, in other words, can I explicitly specify the associated type?