Skip to content

Commit 8f6958f

Browse files
committed
add copyDynamicProperties
1 parent 8fc4f25 commit 8f6958f

2 files changed

Lines changed: 53 additions & 3 deletions

File tree

src/DynamicObj/DynamicObj.fs

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ type DynamicObj() =
2323
// first check the Properties collection for member
2424
this.TryGetPropertyInfo(name)
2525
|> Option.map (fun pi -> pi.GetValue(this))
26-
2726

2827
member this.GetValue (name) =
2928
this.TryGetValue(name).Value
@@ -68,7 +67,7 @@ type DynamicObj() =
6867
match this.TryGetStaticPropertyInfo name with
6968
| Some pi -> Some pi
7069
| None -> this.TryGetDynamicPropertyInfo name
71-
70+
7271
/// Sets property value, creating a new property if none exists
7372
member this.SetValue (name,value) = // private
7473
// first check to see if there's a native property to set
@@ -99,7 +98,6 @@ type DynamicObj() =
9998
| Some _ -> failwith $"Cannot remove value for static, immutable property \"{name}\""
10099
| None -> ()
101100

102-
103101
member this.GetPropertyHelpers (includeInstanceProperties) =
104102
#if FABLE_COMPILER_JAVASCRIPT || FABLE_COMPILER_TYPESCRIPT
105103
FableJS.getPropertyHelpers this
@@ -166,6 +164,23 @@ type DynamicObj() =
166164
#endif
167165
|> Seq.filter (fun kv -> kv.Key.ToLower() <> "properties")
168166

167+
/// Copies all dynamic members of the DynamicObj to the target DynamicObj.
168+
member this.CopyDynamicPropertiesTo(target:#DynamicObj, ?overWrite) =
169+
let overWrite = Option.defaultValue false overWrite
170+
this.GetProperties(false)
171+
|> Seq.iter (fun kv ->
172+
match target.TryGetPropertyInfo kv.Key with
173+
| Some pi when overWrite -> pi.SetValue target kv.Value
174+
| Some _ -> failwith $"Property \"{kv.Key}\" already exists on target object and overWrite was not set to true."
175+
| None -> target.SetValue(kv.Key,kv.Value)
176+
)
177+
178+
/// Returns a new DynamicObj with only the dynamic properties of the original DynamicObj (sans instance properties).
179+
member this.CopyDynamicProperties() =
180+
let target = DynamicObj()
181+
this.CopyDynamicPropertiesTo(target)
182+
target
183+
169184
member this.GetPropertyNames(includeInstanceProperties) =
170185
this.GetProperties(includeInstanceProperties)
171186
|> Seq.map (fun kv -> kv.Key)

tests/DynamicObject.Tests/DynamicObj.fs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,9 +269,44 @@ let tests_print = testList "Print" [
269269
Expect.isTrue print "Print failed for issue 14"
270270
]
271271

272+
let tests_copyDynamicProperties = testList "CopyDynamicProperties" [
273+
testCase "NewObject" <| fun _ ->
274+
let a = DynamicObj()
275+
a.SetValue("a", 1)
276+
a.SetValue("b", 2)
277+
let b = a.CopyDynamicProperties()
278+
Expect.equal a b "Values should be equal"
279+
testCase "ExistingObject" <| fun _ ->
280+
let a = DynamicObj()
281+
a.SetValue("a", 1)
282+
a.SetValue("b", 2)
283+
let b = DynamicObj()
284+
b.SetValue("c", 3)
285+
a.CopyDynamicPropertiesTo(b)
286+
Expect.equal (b.GetValue("a")) 1 "Value a should be copied"
287+
Expect.equal (b.GetValue("b")) 2 "Value b should be copied"
288+
Expect.equal (b.GetValue("c")) 3 "Value c should be unaffected"
289+
testCase "NoOverwrite throws" <| fun _ ->
290+
let a = DynamicObj()
291+
a.SetValue("a", 1)
292+
let b = DynamicObj()
293+
b.SetValue("a", 3)
294+
let f = fun () -> a.CopyDynamicPropertiesTo(b)
295+
Expect.throws f "Should throw because property exists"
296+
testCase "Overwrite" <| fun _ ->
297+
let a = DynamicObj()
298+
a.SetValue("a", 1)
299+
let b = DynamicObj()
300+
b.SetValue("a", 3)
301+
Expect.notEqual a b "Values should not be equal before copying"
302+
a.CopyDynamicPropertiesTo(b, true)
303+
Expect.equal a b "Values should be equal"
304+
]
305+
272306
let main = testList "DynamicObj" [
273307
tests_set
274308
tests_remove
275309
tests_formatString
276310
tests_combine
311+
tests_copyDynamicProperties
277312
]

0 commit comments

Comments
 (0)