September 2017 Update
This commit is contained in:
parent
bba7bfd280
commit
ba8067c3b7
14570 changed files with 153136 additions and 63871 deletions
|
|
@ -1,3 +1,4 @@
|
|||
{{omit from|Rust}}
|
||||
Demonstrate how to dynamically add variables to an object (a class instance) at runtime.
|
||||
|
||||
This is useful when the methods/variables of an instance are based on a data file that isn't available until runtime. Hal Fulton gives an example of creating an OO CSV parser at [http://www.devsource.com/article2/0,1759,1928562,00.asp An Exercise in Metaprogramming with Ruby]. This is referred to as "monkeypatching" by Pythonistas and some others.
|
||||
|
|
|
|||
|
|
@ -1,33 +1,25 @@
|
|||
#define system.
|
||||
#define extensions.
|
||||
import extensions.
|
||||
|
||||
#class Extender :: BaseExtender
|
||||
class Extender :: BaseExtender
|
||||
{
|
||||
#field theField.
|
||||
object prop foo :: theField.
|
||||
|
||||
#constructor new : anObject
|
||||
constructor new : anObject
|
||||
[
|
||||
theObject := anObject.
|
||||
]
|
||||
|
||||
#method foo = theField.
|
||||
|
||||
#method set &foo : aValue
|
||||
[
|
||||
theField := aValue.
|
||||
]
|
||||
}
|
||||
|
||||
#symbol program =
|
||||
program =
|
||||
[
|
||||
#var anObject := 234.
|
||||
var anObject := 234.
|
||||
|
||||
// extending an object with a field
|
||||
anObject := Extender new:anObject.
|
||||
anObject := Extender new(anObject).
|
||||
|
||||
anObject set &foo:"bar".
|
||||
anObject foo := "bar".
|
||||
|
||||
console writeLine:anObject:".foo=":(anObject foo).
|
||||
console printLine(anObject,".foo=",anObject foo).
|
||||
|
||||
console readChar.
|
||||
].
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ include FMS-SILib.f
|
|||
|
||||
:class foo
|
||||
object-list inst-objects \ a dynamically growable object container
|
||||
:m init: inst-objects init: ;m
|
||||
:m add: ( obj -- ) inst-objects add: ;m
|
||||
:m at: ( idx -- obj ) inst-objects at: ;m
|
||||
;class
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
// version 1.1.2
|
||||
|
||||
class SomeClass {
|
||||
val runtimeVariables = mutableMapOf<String, Any>()
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val sc = SomeClass()
|
||||
println("Create two variables at runtime: ")
|
||||
for (i in 1..2) {
|
||||
println(" Variable #$i:")
|
||||
print(" Enter name : ")
|
||||
val name = readLine()!!
|
||||
print(" Enter value : ")
|
||||
val value = readLine()!!
|
||||
sc.runtimeVariables.put(name, value)
|
||||
println()
|
||||
}
|
||||
while (true) {
|
||||
print("Which variable do you want to inspect ? ")
|
||||
val name = readLine()!!
|
||||
val value = sc.runtimeVariables[name]
|
||||
if (value == null) {
|
||||
println("There is no variable of that name, try again")
|
||||
} else {
|
||||
println("Its value is '${sc.runtimeVariables[name]}'")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
d = .dynamicvar~new
|
||||
d~foo = 123
|
||||
say d~foo
|
||||
|
||||
d2 = .dynamicvar2~new
|
||||
d~bar = "Fred"
|
||||
say d~bar
|
||||
|
||||
-- a class that allows dynamic variables. Since this is a mixin, this
|
||||
-- capability can be added to any class using multiple inheritance
|
||||
::class dynamicvar MIXINCLASS object
|
||||
::method init
|
||||
expose variables
|
||||
variables = .directory~new
|
||||
|
||||
-- the UNKNOWN method is invoked for all unknown messages. We turn this
|
||||
-- into either an assignment or a retrieval for the desired item
|
||||
::method unknown
|
||||
expose variables
|
||||
use strict arg messageName, arguments
|
||||
|
||||
-- assignment messages end with '=', which tells us what to do
|
||||
if messageName~right(1) == '=' then do
|
||||
variables[messageName~left(messageName~length - 1)] = arguments[1]
|
||||
end
|
||||
else do
|
||||
return variables[messageName]
|
||||
end
|
||||
|
||||
|
||||
-- this class is not a direct subclass of dynamicvar, but mixes in the
|
||||
-- functionality using multiple inheritance
|
||||
::class dynamicvar2 inherit dynamicvar
|
||||
::method init
|
||||
-- mixin init methods are not automatically invoked, so we must
|
||||
-- explicitly invoke this
|
||||
self~init:.dynamicvar
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
d = .dynamicvar~new
|
||||
d~foo = 123
|
||||
say d~foo
|
||||
|
||||
-- a class that allows dynamic variables. Since this is a mixin, this
|
||||
-- capability can be added to any class using multiple inheritance
|
||||
::class dynamicvar MIXINCLASS object
|
||||
::method init
|
||||
expose variables
|
||||
variables = .directory~new
|
||||
|
||||
-- the unknown method will get invoked any time an unknown method is
|
||||
-- used. This UNKNOWN method will add attribute methods for the given
|
||||
-- name that will be available on all subsequent uses.
|
||||
::method unknown
|
||||
expose variables
|
||||
use strict arg messageName, arguments
|
||||
|
||||
-- check for an assignment or fetch, and get the proper
|
||||
-- method name
|
||||
if messageName~right(1) == '=' then do
|
||||
variableName = messageName~left(messageName~length - 1)
|
||||
end
|
||||
else do
|
||||
variableName = messageName
|
||||
end
|
||||
|
||||
-- define a pair of methods to set and retrieve the instance variable. These are
|
||||
-- created at the object scope
|
||||
self~setMethod(variableName, 'expose' variableName'; return' variableName)
|
||||
self~setMethod(variableName'=', 'expose' variableName'; use strict arg value;' variableName '= value' )
|
||||
|
||||
-- reinvoke the original message. This will now go to the dynamically added
|
||||
methods
|
||||
forward to(self) message(messageName) arguments(arguments)
|
||||
Loading…
Add table
Add a link
Reference in a new issue