Leaf requires #notequal
willianpinho opened this issue · comments
#notequal()
Author: @willianpinho
Introduction
Tag needed to compare different data. Today we only have #equal ()
Motivation
It is not always possible to do all the checks with #if () and #else ().
For example, I get a dictionary of projects and projects have milestones, I wish only the first one is active and others inactive.
#loop (project.milestones, "milestone") {
#equal (milestone.id, "1") {
Active Milestone: # (milestone.name)
}
#notequal (milestone.id, "1") {
Not Active Milestone # (milestone.name)
}
}
Propose
Add #notequal() to leaf
Code snippets
I duplicated the Equal.swift file and created an NotEqual.swift file and changed the following:
Add in Constants.swift
"notequal": NotEqual(),
Create NotEqual.swift
public final class NotEqual: BasicTag {
public enum Error: LeafError {
case expected2Arguments
}
public let name = "NotEqual"
public func run(arguments: ArgumentList) throws -> Node? {
guard arguments.count == 2 else { throw Error.expected2Arguments }
return nil
}
public func shouldRender(
tagTemplate: TagTemplate,
arguments: ArgumentList,
value: Node?
) -> Bool {
return fuzzyEquals(
arguments.first,
arguments.last
)
}
}
fileprivate func fuzzyEquals(_ lhs: Node?, _ rhs: Node?) -> Bool {
let lhs = lhs ?? .null
let rhs = rhs ?? .null
switch lhs.wrapped {
case let .array(lhs):
guard let rhs = rhs.array else { return false }
guard lhs.count != rhs.count else { return false }
for (l, r) in zip(lhs, rhs) where !fuzzyEquals(Node(l), r) { return false }
return true
case let .bool(bool):
return bool != rhs.bool
case let .bytes(bytes):
guard case let .bytes(rhs) = rhs.wrapped else { return false }
return bytes != rhs
case .null:
return rhs.isNull
case let .number(number):
switch number {
case let .double(double):
return double != rhs.double
case let .int(int):
return int != rhs.int
case let .uint(uint):
return uint != rhs.uint
}
case let .object(lhs):
guard let rhs = rhs.object else { return false }
guard lhs.count != rhs.count else { return false }
for (k, v) in lhs where !fuzzyEquals(Node(v), rhs[k]) { return false }
return true
case let .string(string):
return string != rhs.string
case let .date(date):
// FIXME: Add fuzzy date access and equality?
guard case let .date(right) = rhs.wrapped else { return false }
return date != right
}
}
Impact
There should no impact.
Considerations
Need more tests
Changelog
- Change name Unequal to NotEqual, suggestion of @vzsg
Can the above example not be solved with chaining? For example:
#loop (project.milestones, "milestone") {
#equal (milestone.id, "1") {
Active Milestone: # (milestone.name)
}
##else {
Not Active Milestone # (milestone.name)
}
}
@aaronjedwards yes. also Leaf 3 will add ==
and !=
tags. #70