To make our environment easier to use, in function definitions, let's add some macro tricks stolen from Leonidstolen from Leonid:
To make our environment easier to use, in function definitions, let's add some macro tricks stolen from Leonid:
To make our environment easier to use, in function definitions, let's add some macro tricks stolen from Leonid:
ClearAll[symbolToName, deleteOptionDuplicates] symbolToName[sym_Symbol] := SymbolName[sym] symbolToName[arg_] := arg deleteOptionDuplicates[opts:OptionsPattern[]] := GatherBy[Flatten[{opts}], symbolToName@First[#]Composition[symbolToName, &][[AllFirst]][[All, 1]] Now we can define an environment, providing special option-filtering function:
I guess that extraction of OptionsPattern from lhs could be more general.
Now we can define functions like this:
WithoutIf there are duplicates, first option is used regardless of whether it's name is a symbol or a string:
Usually I don't need to store or return filtered options, I just want to pass them to appropriate function. In In such cases other environment, that setts default option values for some functions, can be useful:
ClearAll[withDefaultOptions] withDefaultOptions[base_Symbol, targets:{__Symbol}, opts___]:= Function[body, With[{allOptions=deleteOptionDuplicates[opts, Options[base]]}, Internal`InheritedBlock[targets, Scan[SetOptions[#Scan[ SetOptions[#, FilterRules[allOptions, Options[#]]]&, targets]; targets ]; body ] ], HoldFirst ] withDefaultOptions /: Verbatim[SetDelayed][lhs_Verbatim[SetDelayed][ lhs_, rhs:HoldPattern[withDefaultOptions[_, _,___][_]]] ___][_]] ] := Block[{With}, Attributes[With]={HoldAll}; lhs := Evaluate[rhs] ] withDefaultOptions /: Verbatim[SetDelayed][h_[pre___Verbatim[SetDelayed][ h_[pre___, optsPatt_OptionsPattern, post___], HoldPattern[withDefaultOptions[body_]]] HoldPattern[withDefaultOptions[body_]] ] := h[pre, opts:optsPatt,post] := withDefaultOptions[h withDefaultOptions[ h, Cases[Flatten[{First[optsPatt]}], Except[h, _Symbol]], opts][body] opts ][body] withDefaultOptions /: Verbatim[SetDelayed][ h_[pre___h_[ pre___, namedOptsPatt:Verbatim[Pattern][optsName_, optsPatt_OptionsPattern], post___] post___ ], HoldPattern[withDefaultOptions[body_]] ] := h[pre, namedOptsPatt, post] := withDefaultOptions[h withDefaultOptions[ h, Cases[Flatten[{First[optsPatt]}], Except[h,_Symbol]], optsName][body] optsName ][body] Let's start with a dummy function, to which we'll pass options:
Now a function thethat can accept and pass options to f. It has it'sits own options and some overridden f options, with different defaults.
ClearAll[g]; Options[g] = {"optA" -> "valGA", "optC" -> "valGC"}; g[OptionsPattern[{g, f}]] := withDefaultOptions@{OptionValue[{"optA", "optC"}], f[]} Notice that we don't have to pass anything to f, in body of g. Proper default options for f are set automatically, by withDefaultOptions, based on what'swhat is matched by OptionsPattern and what is inside OptionsPattern.
If option for f is neither given explicitly, nor set as default on g, then default of f is used.
ClearAll[symbolToName, deleteOptionDuplicates] symbolToName[sym_Symbol] := SymbolName[sym] symbolToName[arg_] := arg deleteOptionDuplicates[opts:OptionsPattern[]] := GatherBy[Flatten[{opts}], symbolToName@First[#] &][[All, 1]] Now we can define an environment providing special option-filtering function:
Now we can define functions like this:
Without duplicates:
Usually I don't need to store or return filtered options, I just want to pass them to appropriate function. In such cases other environment can be useful:
ClearAll[withDefaultOptions] withDefaultOptions[base_Symbol, targets:{__Symbol}, opts___]:= Function[body, With[{allOptions=deleteOptionDuplicates[opts, Options[base]]}, Internal`InheritedBlock[targets, Scan[SetOptions[#, FilterRules[allOptions, Options[#]]]&, targets]; body ] ], HoldFirst ] withDefaultOptions /: Verbatim[SetDelayed][lhs_, rhs:HoldPattern[withDefaultOptions[_,_,___][_]]] := Block[{With}, Attributes[With]={HoldAll}; lhs := Evaluate[rhs] ] withDefaultOptions /: Verbatim[SetDelayed][h_[pre___, optsPatt_OptionsPattern, post___], HoldPattern[withDefaultOptions[body_]]] := h[pre, opts:optsPatt,post] := withDefaultOptions[h, Cases[Flatten[{First[optsPatt]}], Except[h, _Symbol]], opts][body] withDefaultOptions /: Verbatim[SetDelayed][ h_[pre___, namedOptsPatt:Verbatim[Pattern][optsName_, optsPatt_OptionsPattern], post___], HoldPattern[withDefaultOptions[body_]] ] := h[pre, namedOptsPatt, post] := withDefaultOptions[h, Cases[Flatten[{First[optsPatt]}], Except[h,_Symbol]], optsName][body] Let's start with a dummy function to which we'll pass options:
Now a function the can accept and pass options to f. It has it's own options and some overridden f options with different defaults.
ClearAll[g]; Options[g] = {"optA" -> "valGA", "optC" -> "valGC"}; g[OptionsPattern[{g, f}]] := withDefaultOptions@{OptionValue[{"optA", "optC"}], f[]} Notice that we don't have to pass anything to f in body of g. Proper default options for f are set automatically by withDefaultOptions based on what's is matched and what is inside OptionsPattern.
If option for f is neither given explicitly nor set as default on g then default of f is used.
ClearAll[symbolToName, deleteOptionDuplicates] symbolToName[sym_Symbol] := SymbolName[sym] symbolToName[arg_] := arg deleteOptionDuplicates[opts:OptionsPattern[]] := GatherBy[Flatten[{opts}], Composition[symbolToName, First]][[All, 1]] Now we can define an environment, providing special option-filtering function:
I guess that extraction of OptionsPattern from lhs could be more general.
Now we can define functions like this:
If there are duplicates, first option is used regardless of whether it's name is a symbol or a string:
Usually I don't need to store or return filtered options, I just want to pass them to appropriate function. In such cases other environment, that setts default option values for some functions, can be useful:
ClearAll[withDefaultOptions] withDefaultOptions[base_Symbol, targets:{__Symbol}, opts___]:= Function[body, With[{allOptions=deleteOptionDuplicates[opts, Options[base]]}, Internal`InheritedBlock[targets, Scan[ SetOptions[#, FilterRules[allOptions, Options[#]]]&, targets ]; body ] ], HoldFirst ] withDefaultOptions /: Verbatim[SetDelayed][ lhs_, rhs:HoldPattern[withDefaultOptions[_, _, ___][_]] ] := Block[{With}, Attributes[With]={HoldAll}; lhs := Evaluate[rhs] ] withDefaultOptions /: Verbatim[SetDelayed][ h_[pre___, optsPatt_OptionsPattern, post___], HoldPattern[withDefaultOptions[body_]] ] := h[pre, opts:optsPatt,post] := withDefaultOptions[ h, Cases[Flatten[{First[optsPatt]}], Except[h, _Symbol]], opts ][body] withDefaultOptions /: Verbatim[SetDelayed][ h_[ pre___, namedOptsPatt:Verbatim[Pattern][optsName_, optsPatt_OptionsPattern], post___ ], HoldPattern[withDefaultOptions[body_]] ] := h[pre, namedOptsPatt, post] := withDefaultOptions[ h, Cases[Flatten[{First[optsPatt]}], Except[h,_Symbol]], optsName ][body] Let's start with a dummy function, to which we'll pass options:
Now a function that can accept and pass options to f. It has its own options and some overridden f options, with different defaults.
ClearAll[g]; Options[g] = {"optA" -> "valGA", "optC" -> "valGC"}; g[OptionsPattern[{g, f}]] := withDefaultOptions@{OptionValue[{"optA", "optC"}], f[]} Notice that we don't have to pass anything to f, in body of g. Proper default options for f are set automatically, by withDefaultOptions, based on what is matched by OptionsPattern and what is inside OptionsPattern.
If option for f is neither given explicitly, nor set as default on g, then default of f is used.
WeLet's start with slightly modified version of mergeRules, that takes into account fact that options can define an environment providing special option-filtering functionhave symbolic or string names and name -> val is treated the same as "name" -> val:
ClearAll[withOptionsClearAll[symbolToName, getOptions]deleteOptionDuplicates] withOptions[base_Symbol, opts___] symbolToName[sym_Symbol] := Function[body, With[ {SymbolName[sym] allOptionssymbolToName[arg_] := DeleteDuplicates[arg Replace[ deleteOptionDuplicates[opts:OptionsPattern[]] := Flatten[GatherBy[Flatten[{opts, Options[base]}], h_[sym_Symbol, val_] :> h[SymbolName[sym],symbolToName@First[#] val]&][[All, {1}1]] ]Now we can define an environment providing special option-filtering function:
ClearAll[withOptions, getOptions] First[#1] ===withOptions[base_Symbol, First[#2]opts___] &:= ]Function[body, With[{allOptions = deleteOptionDuplicates[opts, Options[base]]}, Block[{getOptions = FilterRules[allOptions, Options[#]] &}, body ] ], HoldFirst ] withOptions /: Verbatim[SetDelayed][lhs_, rhs : HoldPattern[withOptions[__][_]]] := Block[{With}, Attributes[With] = {HoldAll}; lhs := Evaluate[rhs] ] withOptions /: Verbatim[SetDelayed][ h_[pre___, optsPatt_OptionsPattern, post___], HoldPattern[withOptions[body_]] ] := h[pre, opts : optsPatt, post] := withOptions[h, opts][body] withOptions /: Verbatim[SetDelayed][ h_[ pre___, namedOptsPatt:Verbatim[Pattern][ optsName_Verbatim[Pattern][optsName_, optsPatt_OptionsPattern ]_OptionsPattern], post___ ], HoldPattern[withOptions[body_]] ] := h[pre, namedOptsPatt, post] := withOptions[h, optsName][body] {TooltipDelay->20} 1 Usually I don't need to store or return filtered options, I just want to pass them to appropriate function. In such cases other environment can be useful:
ClearAll[withDefaultOptions] withDefaultOptions[base_Symbol, targets:{__Symbol}, opts___]:= Function[body, With[{allOptions=deleteOptionDuplicates[opts, Options[base]]}, Internal`InheritedBlock[targets, Scan[SetOptions[#, FilterRules[allOptions, Options[#]]]&, targets]; body ] ], HoldFirst ] withDefaultOptions /: Verbatim[SetDelayed][lhs_, rhs:HoldPattern[withDefaultOptions[_,_,___][_]]] := Block[{With}, Attributes[With]={HoldAll}; lhs := Evaluate[rhs] ] withDefaultOptions /: Verbatim[SetDelayed][h_[pre___, optsPatt_OptionsPattern, post___], HoldPattern[withDefaultOptions[body_]]] := h[pre, opts:optsPatt,post] := withDefaultOptions[h, Cases[Flatten[{First[optsPatt]}], Except[h, _Symbol]], opts][body] withDefaultOptions /: Verbatim[SetDelayed][ h_[pre___, namedOptsPatt:Verbatim[Pattern][optsName_, optsPatt_OptionsPattern], post___], HoldPattern[withDefaultOptions[body_]] ] := h[pre, namedOptsPatt, post] := withDefaultOptions[h, Cases[Flatten[{First[optsPatt]}], Except[h,_Symbol]], optsName][body] Let's start with a dummy function to which we'll pass options:
ClearAll[f]; Options[f] = {"optA" -> "valFA", "optB" -> "valFB"}; f[OptionsPattern[]] := OptionValue[{"optA", "optB"}] Now a function the can accept and pass options to f. It has it's own options and some overridden f options with different defaults.
ClearAll[g]; Options[g] = {"optA" -> "valGA", "optC" -> "valGC"}; g[OptionsPattern[{g, f}]] := withDefaultOptions@{OptionValue[{"optA", "optC"}], f[]} Notice that we don't have to pass anything to f in body of g. Proper default options for f are set automatically by withDefaultOptions based on what's is matched and what is inside OptionsPattern.
If option for f is neither given explicitly nor set as default on g then default of f is used.
g[] (* {{"valGA", "valGC"}, {"valGA", "valFB"}} *) g["optA" -> 1] (* {{1, "valGC"}, {1, "valFB"}} *) g["optB" -> 1] (* {{"valGA", "valGC"}, {"valGA", 1}} *) g["optC" -> 1] (* {{"valGA", 1}, {"valGA", "valFB"}} *) We can define an environment providing special option-filtering function:
ClearAll[withOptions, getOptions] withOptions[base_Symbol, opts___] := Function[body, With[ { allOptions = DeleteDuplicates[ Replace[ Flatten[{opts, Options[base]}], h_[sym_Symbol, val_] :> h[SymbolName[sym], val], {1} ], First[#1] === First[#2] & ] }, Block[{getOptions = FilterRules[allOptions, Options[#]] &}, body ] ], HoldFirst ] withOptions /: Verbatim[SetDelayed][lhs_, rhs : HoldPattern[withOptions[__][_]]] := Block[{With}, Attributes[With] = {HoldAll}; lhs := Evaluate[rhs] ] withOptions /: Verbatim[SetDelayed][ h_[pre___, optsPatt_OptionsPattern, post___], HoldPattern[withOptions[body_]] ] := h[pre, opts : optsPatt, post] := withOptions[h, opts][body] withOptions /: Verbatim[SetDelayed][ h_[ pre___, namedOptsPatt:Verbatim[Pattern][ optsName_, optsPatt_OptionsPattern ], post___ ], HoldPattern[withOptions[body_]] ] := h[pre, namedOptsPatt, post] := withOptions[h, optsName][body] {TooltipDelay->20} 1 Let's start with slightly modified version of mergeRules, that takes into account fact that options can have symbolic or string names and name -> val is treated the same as "name" -> val:
ClearAll[symbolToName, deleteOptionDuplicates] symbolToName[sym_Symbol] := SymbolName[sym] symbolToName[arg_] := arg deleteOptionDuplicates[opts:OptionsPattern[]] := GatherBy[Flatten[{opts}], symbolToName@First[#] &][[All, 1]] Now we can define an environment providing special option-filtering function:
ClearAll[withOptions, getOptions] withOptions[base_Symbol, opts___] := Function[body, With[{allOptions = deleteOptionDuplicates[opts, Options[base]]}, Block[{getOptions = FilterRules[allOptions, Options[#]] &}, body ] ], HoldFirst ] withOptions /: Verbatim[SetDelayed][lhs_, rhs : HoldPattern[withOptions[__][_]]] := Block[{With}, Attributes[With] = {HoldAll}; lhs := Evaluate[rhs] ] withOptions /: Verbatim[SetDelayed][ h_[pre___, optsPatt_OptionsPattern, post___], HoldPattern[withOptions[body_]] ] := h[pre, opts : optsPatt, post] := withOptions[h, opts][body] withOptions /: Verbatim[SetDelayed][ h_[ pre___, namedOptsPatt:Verbatim[Pattern][optsName_, _OptionsPattern], post___ ], HoldPattern[withOptions[body_]] ] := h[pre, namedOptsPatt, post] := withOptions[h, optsName][body] {TooltipDelay->20} 1 Usually I don't need to store or return filtered options, I just want to pass them to appropriate function. In such cases other environment can be useful:
ClearAll[withDefaultOptions] withDefaultOptions[base_Symbol, targets:{__Symbol}, opts___]:= Function[body, With[{allOptions=deleteOptionDuplicates[opts, Options[base]]}, Internal`InheritedBlock[targets, Scan[SetOptions[#, FilterRules[allOptions, Options[#]]]&, targets]; body ] ], HoldFirst ] withDefaultOptions /: Verbatim[SetDelayed][lhs_, rhs:HoldPattern[withDefaultOptions[_,_,___][_]]] := Block[{With}, Attributes[With]={HoldAll}; lhs := Evaluate[rhs] ] withDefaultOptions /: Verbatim[SetDelayed][h_[pre___, optsPatt_OptionsPattern, post___], HoldPattern[withDefaultOptions[body_]]] := h[pre, opts:optsPatt,post] := withDefaultOptions[h, Cases[Flatten[{First[optsPatt]}], Except[h, _Symbol]], opts][body] withDefaultOptions /: Verbatim[SetDelayed][ h_[pre___, namedOptsPatt:Verbatim[Pattern][optsName_, optsPatt_OptionsPattern], post___], HoldPattern[withDefaultOptions[body_]] ] := h[pre, namedOptsPatt, post] := withDefaultOptions[h, Cases[Flatten[{First[optsPatt]}], Except[h,_Symbol]], optsName][body] Let's start with a dummy function to which we'll pass options:
ClearAll[f]; Options[f] = {"optA" -> "valFA", "optB" -> "valFB"}; f[OptionsPattern[]] := OptionValue[{"optA", "optB"}] Now a function the can accept and pass options to f. It has it's own options and some overridden f options with different defaults.
ClearAll[g]; Options[g] = {"optA" -> "valGA", "optC" -> "valGC"}; g[OptionsPattern[{g, f}]] := withDefaultOptions@{OptionValue[{"optA", "optC"}], f[]} Notice that we don't have to pass anything to f in body of g. Proper default options for f are set automatically by withDefaultOptions based on what's is matched and what is inside OptionsPattern.
If option for f is neither given explicitly nor set as default on g then default of f is used.
g[] (* {{"valGA", "valGC"}, {"valGA", "valFB"}} *) g["optA" -> 1] (* {{1, "valGC"}, {1, "valFB"}} *) g["optB" -> 1] (* {{"valGA", "valGC"}, {"valGA", 1}} *) g["optC" -> 1] (* {{"valGA", 1}, {"valGA", "valFB"}} *)