5
$\begingroup$
BeginPackage["foo`"];
    bar;
Begin["`Private`"];    
    bar[] := bar[ $Context, $ContextPath];    
End[];
EndPackage[];

So I'd like to have all information about foo` stored in an expression.

It may be useful in something like How can I include functions from a package into a CDF file? where the package is spread over many files.

  • DumpSave is not portable enough

  • Save saves $Context and $ContextPath (everything what is not protected) together with all definitions so loading it will affect environment.

    I can load it within additional Begin/EndPackage but I don't like it.

  • I don't know how to use Language` functions to do this.

So I can cook up a workaround but I'd like to ask if I'm not missing something obvious here.

Summing up, compressContext should take context name as input and output compressed string which one can later Get @ StringToStream @ Uncompress @ string.

Or whatever that can be used to load context back.

$\endgroup$
3
$\begingroup$

Update

It seems you want to avoid saving definitions for any System` symbols. Instead of blocking all of the unprotected symbols that could be used, another idea is to modify the InputForm format of Set and TagSet so that they are suppressed when applied to System` symbols. For example:

compressContext[context_] := Internal`InheritedBlock[{Set, TagSet, Internal`$ContextMarks = True},
    Unprotect[Set, TagSet];
    Format[HoldPattern@TagSet[s_Symbol, __], InputForm] /; Context[Unevaluated[s]]=="System`":=OutputForm[""];
    Format[HoldPattern@Set[s_Symbol, __], InputForm] /; Context[Unevaluated[s]]=="System`":=OutputForm[""];

    Compress @ ToString[
        Join @@ ToExpression[Names[context<>"*"], InputForm, FullDefinition],
        InputForm
    ]
]

For your example:

BeginPackage["foo`"];
    bar;
Begin["`Private`"];    
    bar[] := bar[ $Context, $ContextPath];    
End[];
EndPackage[];

Applying compressContext and uncompressing:

compressContext["foo`"]

Uncompress @ %

"1:eJxTTMoPCvZhYGBIy89PSEosio5VsLJVgHGCK4tLUnMTVJzz80pSK0p0FNAEAhJLMmJjDAyNFEA\ EnAEAuIobbg=="

"foo`bar[] := foo`bar[System`\$Context, System`\$ContextPath]

"

The space where the $Context and $ContextPath definitions used to live has been removed.

Initial answer

How about blocking $Context and $ContextPath so that they are protected?

Block[{$Context,$ContextPath},
    SetAttributes[{$Context, $ContextPath}, Protected];
    Save["kuba.m","foo`"]
]

FilePrint["kuba.m"]

foo`bar[] := foo`bar[$Context, $ContextPath]

P.S. I'm not sure what role compressedContext is supposed to play here.

$\endgroup$
  • $\begingroup$ +1 I will have to modify it to filter out everything except of MyPackageContextName`*`* because if I have e.g. Needs["PacletManager`"] in my package and e.g. CreatePaclet is mentioned inside, it will be stored. And it is quite natural not to expect this ;) $\endgroup$ – Kuba Dec 15 '17 at 7:04
  • $\begingroup$ @Kuba Do you have access to the file where the package lives? If so, you couldn't you just compress that file? $\endgroup$ – Carl Woll Dec 15 '17 at 15:52
  • $\begingroup$ The point of this question is to go beyond this :) I've already linked a topic where this is done. But see e.g. JLink` implementation, or any other with multiple files and custom loading order. This topic is for them. (ofc I am not interested in packing built in packages but custom) $\endgroup$ – Kuba Dec 18 '17 at 7:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.