«Converting an environment in a prototype object» by julian.rohrhuber

on 11 Jul'21 15:11 in environmentprototyping

/* I often like to write out a library as an environment, like:

~start_sound = { |freq, amp| <...> }; ~start_high_pitch_sound = { |amp| ~start_sound.(14000, amp) };

… and then use loadRelative to load that library.

This, however has the problem that you can't stick the whole library into an environment that you call from the outside. e.g.

q = (); q.use { resolveRelative("/library.scd") };

and then trying:

q.start_sound(700, 0.1); q.start_high_pitch_sound(0.1);

will not work. Firstly, it will expect the environment as first argument of each function, second, it won't find a function like ~start_sound from within the call context.

Here is a way to convert an environment as needed.

*/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
~constructPseudoMethods = { |envir|
	var newEnvir = envir.collect { |value|
		var argNames, argBlock, namesBlock, code, func;
		if(value.isKindOf(Function)) {
			func = value;
			argNames = func.def.argumentString(withDefaultValues: true);
			namesBlock =  func.def.argumentString(withDefaultValues: false);
			argBlock = if(argNames.notNil) { "|self, "  ++ argNames ++ "|" };
			code = "{ |func, envir| { % envir.use { func.value(%) } } }".format(argBlock ? "", namesBlock ? "");
			//code.postln;
			code.interpret.value(func, envir)
		} {
			value
		}
	};
	newEnvir.know = true; // we want a prototype object style environment
};
raw 648 chars (focus & ctrl+a+c to copy)
reception
comments
julian.rohrhuber user 11 Jul'21 15:16

Note that this doesn't yet work with ellipsis arguments.