-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathWOAssociation.swift
More file actions
136 lines (107 loc) · 3.95 KB
/
WOAssociation.swift
File metadata and controls
136 lines (107 loc) · 3.95 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
//
// WOAssociation.swift
// SwiftObjects
//
// Created by Helge Hess on 11.05.18.
// Copyright © 2018-2021 ZeeZide. All rights reserved.
//
/**
* Associations define how dynamic elements (stateless, non-WOComponent
* template elements) pull and push their 'bindings'.
*
* The most common implementors are:
* `WOKeyPathAssociation`, which pushes/pulls values into/from the current
* component in the context, and
* `WOValueAssociation`, which just wraps a constant value in the WOAssociation
* API.
*
* But in addition there are associations which evaluate OGNL expressions,
* which resolve their value as localization keys or which resolve string
* patterns in a certain context. etc etc
*/
public protocol WOAssociation : AnyObject {
// MARK: - Reflection
/**
* Returns true if the association always returns the same value. This can be
* used by dynamic elements to cache the value (and discard the association
* wrapper).
*
* @return true if the value of the association never changes, false otherwise
*/
var isValueConstant : Bool { get }
/**
* Returns true if the association accepts new values. Eg a constant
* association obviously doesn't accept new values. A KVC association to a
* target which does not have a <code>set</code> accessor could also return
* false (but currently does not ...).
*
* @return true if the value of the association can be set, false otherwise
*/
var isValueSettable : Bool { get }
/**
* Returns true if the association always returns the same value for the
* specified cursor (usually a component). This can be used by dynamic
* elements to cache the value.
*
* @return true if the value of the association does not change
*/
func isValueConstantInComponent(_ cursor: Any?) -> Bool
/**
* Returns true if the association can accept new values for the given cursor
* (usually a WOComponent). A KVC association to a target which does not have
* a `set` accessor could also return false.
*
* @return true if the value of the association can be set, false otherwise
*/
func isValueSettableInComponent(_ cursor: Any?) -> Bool
var keyPath : String? { get }
// MARK: - Values
func setValue(_ value: Any?, in component: Any?) throws
func value(in component: Any?) -> Any?
// MARK: - Specific Values
func setBoolValue(_ value: Bool, in component: Any?) throws
func boolValue(in component: Any?) -> Bool
func setIntValue(_ value: Int, in component: Any?) throws
func intValue(in component: Any?) -> Int
func setStringValue(_ value: String?, in component: Any?) throws
func stringValue(in component: Any?) -> String?
}
// MARK: - Default implementation
public extension WOAssociation {
var isValueConstant : Bool { return false }
var isValueSettable : Bool { return true }
func isValueConstantInComponent(_ cursor: Any?) -> Bool {
return isValueConstant
}
func isValueSettableInComponent(_ cursor: Any?) -> Bool {
return isValueSettable
}
var keyPath : String? { return nil }
// MARK: - Values
func setValue(_ value: Any?, in component: Any?) {
// TBD: we could throw, but GETobjects used to be quite forgiving ;-)
}
func value(in component: Any?) -> Any? {
return nil
}
// MARK: - Specific Values
func setBoolValue(_ value: Bool, in component: Any?) throws {
try setValue(value, in: component)
}
func boolValue(in component: Any?) -> Bool {
return UObject.boolValue(value(in: component))
}
func setIntValue(_ value: Int, in component: Any?) throws {
try setValue(value, in: component)
}
func intValue(in component: Any?) -> Int {
return UObject.intValue(value(in: component))
}
func setStringValue(_ value: String?, in component: Any?) throws {
try setValue(value, in: component)
}
func stringValue(in component: Any?) -> String? {
guard let v = value(in: component) else { return nil }
return UObject.stringValue(v)
}
}