23
$\begingroup$

As part of my never-ending goal of getting Mathematica code to be as easily shared as python packages I was recently thinking about how to make code easy to share.

So what's are some good ways to share code snippets, if, say, someone wants to put some code out onto the internet, but doesn't want to make it a package worthy of putting in a GitHub repo or putting in a paclet server?

$\endgroup$
  • 3
    $\begingroup$ How about posting the snippets here? All you really need to do extra is to phrase things in the form of a question... or you can wait until someone else asks something related and then post your snippet as an answer. $\endgroup$ – bill s Dec 4 '17 at 1:09
  • $\begingroup$ @bills that's what I tend to do, but sometimes you don't want the snippet pegged to a specific use case. And it can be difficult to programmatically load a SO snippet from the question / answer URL, particularly when multiple snippets are provided. $\endgroup$ – b3m2a1 Dec 4 '17 at 1:12
  • $\begingroup$ @bills you may also want to share code in a private space/repo. $\endgroup$ – Kuba Dec 5 '17 at 6:26
  • $\begingroup$ @Kuba good point. And having a private space to publish stuff just lets you publish more, which can be either good or bad. No need to rephrase things as a question that just wastes space on MSE. $\endgroup$ – b3m2a1 Dec 5 '17 at 6:28
14
$\begingroup$

Gists API Snippets

My first version of this involves the Gists API for GitHub. As Leonid notes, the Gists API makes sharing small pieces of code pretty easy.

I also cooked this into my general GitHub service connection to be able to export directly from a notebook, e.g.:

nb =
   CreateDocument[
     Cell[
       BoxData@ToBoxes@Unevaluated[myFunc[x_] := x^2],
       "Code"
       ],
     WindowTitle -> "myFunc"
     ];
$so = ServiceConnect["GitHub"];
gist =
  $so["CreateGist",
     "files" -> nb,
     "public" -> "true"
     ];
gist[{"id", "html_url"}]

(*Out:*)

url ds

Checking what’s at the URL:

confirmation

We see that it got added as we’d hope.

Then we can pull a URL that others can load this from:

gist["files", "myFunc", "raw_url"]

(*Out:*)

URL["https://gist.githubusercontent.com/b3m2a1/479c4b9ee826245a4f72d5150beac413/raw/bcd1d5cf5254a965534126a5e04e036bb2876cca/myFunc"]

And they can load the code like so:

myFunc // DownValues
Import[First@gist["files", "myFunc", "raw_url"], "Package"];
myFunc // DownValues

(*Out:*)

{}

(*Out:*)

{HoldPattern[myFunc[x_]] :> x^2}

Now, this isn’t as smooth or as trivial as using the cloud to do this (and both are free, so that’s not really too much of a concern), but people might have their reasons for preferring GitHub.

Paclet Installation

Here’s how you can install this connection:

(* If you've already installed this, use PacletUpdate instead *)
PacletInstall["ServiceConnection_GitHub",
  "Site" ->
    "https://www.wolframcloud.com/app/objects/b3m2a1.paclets/PacletServer"
  ]

Helper Function

A function people might find useful is this:

GHExtractGist[r_] :=
  Replace[
    r,
    {
      nb_NotebookObject :>
       GHExtractGist@
        Replace[
          SelectedCells[nb],
          {} :> Cells[nb, CellStyle -> {"Input" | "Code"}]
          ],
      cl : {__CellObject} :>
       KeyValueMap[
         Replace[
             Quiet@FileNameTake@NotebookFileName[#],
             Except[_String] :>
              AbsoluteCurrentValue[#, WindowTitle]
             ] ->
           {
             "content" ->
               FrontEndExecute[
                  ExportPacket[
                    Cell[
                      BoxData@
                       Replace[
                         NotebookRead@#2,
                         Cell[BoxData[{d__}], ___] :> d,
                         1
                         ]
                      ],
                    "InputText"
                    ]
                  ][[1]]
             } &,
         GroupBy[cl, ParentNotebook]
         ],
      cl_CellObject :> GHExtractGist@{cl},
      t : _TextCell | _ExpressionCell | _Cell :>
       {
         Replace[
            Quiet@FileNameTake@NotebookFileName[InputNotebook[]],
            Except[_String] :>
             AbsoluteCurrentValue[InputNotebook[], WindowTitle]
            ] ->
          {
            "content" ->
              FrontEndExecute[
                 ExportPacket[

           Replace[t, (TextCell | ExpressionCell)[e_, ___] :> Cell[e]],
                   "InputText"
                   ]
                 ][[1]]
            }
         },
      f : (_File | _String)?FileExistsQ :>
       {
         Replace[f, File[fil_] :> fil] ->
          {
            "content" -> Import[f, "Text"]
            }
         },
      _ -> $Failed
      }
    ]

It simply extracts and formats the code parts of a notebook. I use it to extract Gists automatically.

$\endgroup$
9
$\begingroup$

Wolfram Cloud Snippet Uploader

Here’s probably the easiest method I know of: use the cloud. I already use it for lots of my things. I have ~4 free accounts that I use for different distribution and testing purposes, so using it for snippets seems obvious.

A little snippet uploader can be written like so: (note that there might be a better way to write this)

exportNotebookSnippet // Clear;
Options[exportNotebookSnippet] =
  Options[CloudObject];
exportNotebookSnippet[
    notebook :
     _NotebookObject | _CellObject | _BoxObject | {(_CellObject | \
_BoxObject) ..} | Automatic : Automatic,
    uri : _String | None | Automatic : Automatic,
    ops : OptionsPattern[]
    ] :=
   Module[{nb, cells, chunk, tmp, path},
     nb = Replace[notebook, Automatic :> SelectedNotebook[]];
     cells =
      Replace[Flatten@List@nb,
        {_NotebookObject} :>

      Replace[SelectedCells[nb], {} :> 
        Cells[nb, CellStyle -> {"Input" | "Code"}]]
        ];
     chunk =
      FrontEndExecute[
         ExportPacket[
           Cell[
             BoxData@
              Replace[
                NotebookRead@cells,
                Cell[BoxData[{d__}], ___] :> d,
                1
                ]
             ],
           "InputText"
           ]
         ][[1]];
     tmp = Export[CreateFile[], chunk, "Text"];
     path =
       Replace[uri, 
        {
          None :> Sequence @@ {},
          Automatic :>
           Switch[nb,
              _NotebookObject,
             Replace[FileBaseName@Quiet@NotebookFileName[nb],
               $Failed :> AbsoluteCurrentValue[nb, WindowTitle]
	               ],
	             _,
	             With[{n = ParentNotebook@cells[[1]]},
	               Replace[FileBaseName@Quiet@NotebookFileName[n],
	                  $Failed :> AbsoluteCurrentValue[n, WindowTitle]
                  ] <> "-snippet-" <>
                Replace[
                  FirstCase[
                    NotebookRead@cells[[1]],
                    (ExpressionUUID -> s_) :> s,
                    None,
                    \[Infinity]
                    ],
                  None -> ToString[cells[[1, 1]]]
                  ]
               ]
             ]
          }];
     (DeleteFile[tmp]; Take[#, 1]) &@
      CopyFile[tmp,
        CloudObject[path, ops],
         "MIMEType" -> ImportExport`GetMIMEType["Package"][[1]]
        ]
     ];

Then upload like so:

snippetObj = 
 exportNotebookSnippet[PreviousCell[], Permissions -> "Public"]

(*Out:*)

CloudObject["https://www.wolframcloud.com/objects/b3m2a1.testing/\
answer-snippet-167329"]

And you can conveniently import that:

Clear[exportNotebookSnippet];
CloudImport[snippetObj];
DownValues[exportNotebookSnippet]

(*Out:*)

{HoldPattern[
   exportNotebookSnippet[
    notebook : _NotebookObject | _CellObject | _BoxObject | \
{(_CellObject | _BoxObject) ..} | Automatic : Automatic, 
    uri : _String | None | Automatic : Automatic, 
    ops : OptionsPattern[]]] :> 
  Module[{nb, cells, chunk, tmp, path}, 
   nb = Replace[notebook, Automatic :> SelectedNotebook[]]; 
   cells = Replace[
     Flatten[{nb}], {_NotebookObject} :> 
      Replace[SelectedCells[nb], {} :> 
        Cells[nb, CellStyle -> {"Input" | "Code"}]]]; 
   chunk = FrontEndExecute[
      ExportPacket[
       Cell[BoxData[
         Replace[NotebookRead[cells], Cell[BoxData[{d__}], ___] :> d, 
          1]]], "InputText"]][[1]]; 
   tmp = Export[CreateFile[], chunk, "Text"]; 
   path = Replace[uri, {None :> Sequence @@ {}, Automatic :> Switch[nb,
        _NotebookObject, 
        Replace[FileBaseName[Quiet[NotebookFileName[nb]]], $Failed :> 
	          AbsoluteCurrentValue[nb, WindowTitle]],
	        _, 
	        With[{n = ParentNotebook[cells[[1]]]}, 
	         Replace[FileBaseName[Quiet[NotebookFileName[n]]], $Failed :> 
            AbsoluteCurrentValue[n, WindowTitle]] <> "-snippet-" <> 
          Replace[FirstCase[
            NotebookRead[cells[[1]]], (ExpressionUUID -> s_) :> s, 
            None, \[Infinity]], 
           None -> ToString[cells[[1, 1]]]]]]}]; ((DeleteFile[tmp]; 
       Take[#1, 1]) &)[
    CopyFile[tmp, CloudObject[path, ops], 
     "MIMEType" -> ImportExport`GetMIMEType["Package"][[1]]]]]}
$\endgroup$
  • 1
    $\begingroup$ Here is a serious question from a serious Mathematica user: Why does this process have to be so complicated? Why isn't it possible to upload Mathematica code by copy and paste? Thank you. $\endgroup$ – Ralph Dratman Dec 6 '17 at 4:52
  • $\begingroup$ @RalphDratman I wanted to do it wholly from within Mathematica. With copy-and-paste all sorts of things are possible, but not necessarily as easy to tweak and build with. $\endgroup$ – b3m2a1 Feb 13 '18 at 21:50

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.