mirror of
https://github.com/yabwon/SAS_PACKAGES.git
synced 2025-12-11 11:14:35 +00:00
Compare commits
151 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7aca779d60 | ||
|
|
ca3a001f65 | ||
|
|
fa2d53eaf8 | ||
|
|
bd81f5d36e | ||
|
|
96c8234a58 | ||
|
|
669a8e0a1d | ||
|
|
b48260977b | ||
|
|
92dc813146 | ||
|
|
c5756d3979 | ||
|
|
9c9ebe63d1 | ||
|
|
5be2d8c76c | ||
|
|
ee5d4de333 | ||
|
|
c4bb3ec6a6 | ||
|
|
d43db77a45 | ||
|
|
7b99a5651d | ||
|
|
7e5c98976b | ||
|
|
9f4143af53 | ||
|
|
bd8e378829 | ||
|
|
dc3bedae3f | ||
|
|
af94d49a79 | ||
|
|
4069f066aa | ||
|
|
266a1fe1a7 | ||
|
|
3111b6667e | ||
|
|
e3b86f1157 | ||
|
|
c9b388b661 | ||
|
|
82681a3f91 | ||
|
|
cb4f82eac9 | ||
|
|
98e2125028 | ||
|
|
77d6b0a2e5 | ||
|
|
c1182ea8cb | ||
|
|
ddfac01483 | ||
|
|
d8c8cfc9e3 | ||
|
|
c126e7c0a3 | ||
|
|
e7883142b8 | ||
|
|
e55275d308 | ||
|
|
72a77edb16 | ||
|
|
dbe8dbc938 | ||
|
|
9168f4b4f0 | ||
|
|
2f5cb056b1 | ||
|
|
44be31bd84 | ||
|
|
227e522f5b | ||
|
|
9a3ff6a265 | ||
|
|
62a14b4560 | ||
|
|
0bd2f6f2d8 | ||
|
|
e3c42e6441 | ||
|
|
8807a1560e | ||
|
|
a282349c86 | ||
|
|
6dc4f22103 | ||
|
|
2fd23f5b35 | ||
|
|
f3f4747df6 | ||
|
|
edca6a8a8c | ||
|
|
f59c2a4893 | ||
|
|
b4314c03e3 | ||
|
|
3a824b4d8b | ||
|
|
ba4b5f8c32 | ||
|
|
15e7d48adf | ||
|
|
a5b4f117cc | ||
|
|
b3ea02b7b0 | ||
|
|
e4dfc6a863 | ||
|
|
7d083e879c | ||
|
|
35e6ff8d5e | ||
|
|
5bd013c925 | ||
|
|
2ad317db01 | ||
|
|
6c38872ee2 | ||
|
|
d35ac328cc | ||
|
|
e3a813b257 | ||
|
|
67bd3abd58 | ||
|
|
1968330049 | ||
|
|
7e202f81ff | ||
|
|
26d9c735fe | ||
|
|
11c0b95d7e | ||
|
|
be89c6b9c6 | ||
|
|
17b1239087 | ||
|
|
bbba37d8eb | ||
|
|
6ccc07a5bb | ||
|
|
b5e15bda11 | ||
|
|
160c1bc9d3 | ||
|
|
76297dc5d8 | ||
|
|
ea866123d9 | ||
|
|
75029a488f | ||
|
|
642bc5ba72 | ||
|
|
6d10426474 | ||
|
|
7048adb3b6 | ||
|
|
5ab1f4c73e | ||
|
|
4452d9ee7c | ||
|
|
df04e48656 | ||
|
|
76c7793e34 | ||
|
|
cc6528bbeb | ||
|
|
2bb633a55b | ||
|
|
10009b33ae | ||
|
|
68e85eb5ba | ||
|
|
0778a71ada | ||
|
|
0cf35c15a7 | ||
|
|
00c63c4d8a | ||
|
|
9dedc53c31 | ||
|
|
a7d61f6026 | ||
|
|
9f92b5f5d4 | ||
|
|
a95c672693 | ||
|
|
9bccc4329a | ||
|
|
b76b1ed9eb | ||
|
|
942879a5b8 | ||
|
|
fe631f9e44 | ||
|
|
3f380b4e64 | ||
|
|
02de8f0bc0 | ||
|
|
7fa70d5ad4 | ||
|
|
98e822bde2 | ||
|
|
2026254b96 | ||
|
|
9ff8fd506c | ||
|
|
7be17a3a57 | ||
|
|
e2e54b8025 | ||
|
|
cdf07fc232 | ||
|
|
bcbd078b7d | ||
|
|
c12260fdcd | ||
|
|
b45b79fd3c | ||
|
|
2ce8a83499 | ||
|
|
59cda13330 | ||
|
|
f7485ce6c4 | ||
|
|
8f3cbe1b92 | ||
|
|
bc36780cee | ||
|
|
3a0fc83433 | ||
|
|
b8905ca4a7 | ||
|
|
47426131a5 | ||
|
|
8a23978694 | ||
|
|
f3f3bc3688 | ||
|
|
c2e06995f5 | ||
|
|
40f3a00cb2 | ||
|
|
6f1f30fef9 | ||
|
|
78f202b150 | ||
|
|
97d393bb71 | ||
|
|
98af4c8bc3 | ||
|
|
c04d9c4eb2 | ||
|
|
8b65e85f3a | ||
|
|
582c12d908 | ||
|
|
742e4ac3d3 | ||
|
|
74360b4cca | ||
|
|
aba2ee4f44 | ||
|
|
55f4e35e0e | ||
|
|
50f307f370 | ||
|
|
3cd73a858d | ||
|
|
acd3a4872d | ||
|
|
36b766da9a | ||
|
|
b1e61b587a | ||
|
|
34b46d1e85 | ||
|
|
41a314d3f8 | ||
|
|
f021a2fd08 | ||
|
|
9277a83561 | ||
|
|
e505c3658e | ||
|
|
222d88511a | ||
|
|
ac10ab21ff | ||
|
|
c45c0d9921 | ||
|
|
0a9d070055 |
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) since 2019 Bartosz Jablonski
|
||||
Copyright (c) 2019 - 2023 Bartosz Jablonski
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
289
README.md
289
README.md
@@ -1,4 +1,6 @@
|
||||
# SAS_PACKAGES - a SAS Packages Framework and Repository
|
||||
# SAS_PACKAGES - a SAS Packages Framework
|
||||
|
||||
---
|
||||
|
||||
## Intro:
|
||||
|
||||
@@ -6,7 +8,15 @@ A **SAS package** is an automatically generated, single, stand alone *zip* file
|
||||
|
||||
The *purpose of a package* is to be a simple, and easy to access, code sharing medium, which will allow: on the one hand, to separate the code complex dependencies created by the developer from the user experience with the final product and, on the other hand, reduce developer's and user's unnecessary frustration related to a remote deployment process.
|
||||
|
||||
In this repository we are presenting the **SAS Packages Framework** which allows to develop and use SAS packages. The latest version of SPF is **`20201115`**.
|
||||
In this repository we are presenting the **SAS Packages Framework** which allows to develop and use SAS packages.
|
||||
|
||||
Don't forget to **STAR** (:star:) the repository! :-)
|
||||
|
||||
---
|
||||
|
||||
### Current version:
|
||||
|
||||
**The latest version** of SPF is **`20231210`**.
|
||||
|
||||
To get started with SAS Packages try this [**`Getting Started with SAS Packages`**](https://github.com/yabwon/SAS_PACKAGES/blob/main/SPF/Documentation/Getting_Started_with_SAS_Packages.pdf "Getting Started with SAS Packages") presentation (see the `./SPF/Documentation` directory).
|
||||
|
||||
@@ -14,133 +24,228 @@ The documentation and more advance reading would be the [**`SAS(r) packages - th
|
||||
|
||||
Short description of the SAS Packages Framework macros can be found [here](https://github.com/yabwon/SAS_PACKAGES/blob/main/SPF/SPFinit.md "Short description of the SAS Packages Framework macros")
|
||||
|
||||
**General overview video:**
|
||||
- [SAS Global Forum 2020 V.E.](https://www.youtube.com/watch?v=qCkb-bx0Dv8&t=0s "SGF2020") (April 2020)
|
||||
- [Sasensei International Dojo](https://www.youtube.com/watch?v=BFhdUBQgjYQ&t=0s "SID no. 1") (April 2020)
|
||||
- [SAS dla Administratorów i Praktyków 2020](https://www.youtube.com/watch?v=mXuep2k48Z8&feature=youtu.be&t=0s "SASAiP2020") (October 2020, in Polish)
|
||||
### Recordings and Presentations:
|
||||
|
||||
Videos presenting the SPF and packages, from various conferences and meetups (the newer the better):
|
||||
|
||||
- ["SAS Packages: The Way to Share" - SAS Global Forum 2020 V.E.](https://www.youtube.com/watch?v=qCkb-bx0Dv8&t=0s "SGF2020") (April 2020, ~20 minutes, general overview but with a bit obsolete technical details)
|
||||
- ["SAS Packages: The Way to Share" - SaSensei International Dojo No. 1](https://www.youtube.com/watch?v=BFhdUBQgjYQ&t=0s "SID no. 1") (April 2020, ~28 minutes, general overview but with a bit obsolete technical details)
|
||||
- ["Co nowego z pakietami SAS?" - SAS dla Administratorów i Praktyków 2020](https://www.youtube.com/watch?v=mXuep2k48Z8&feature=youtu.be&t=0s "SASAiP2020") (October 2020, in Polish, ~41 minutes, general overview and technical details how to use SPF)
|
||||
- ["SAS Packages - The Way to Share" - Boston Area SAS Users Group webinar](https://www.basug.org/videos?wix-vod-video-id=78067e61413d43d3a6951974b3bc3014&wix-vod-comp-id=comp-klv807gt "BASUG") (November 2020, ~59 minutes, general overview and technical details how to use SPF)
|
||||
- ["My First SAS Package: A How-To" - SAS Global Forum 2021 V.E.](https://www.youtube.com/watch?v=hqexaQtGw88 "SGF2021") (May 20th 2021, ~30 minutes, technical workshop on how to create a package)
|
||||
- ["Kod SASowy ukryty na widoku" - SAS dla Administratorów i Praktyków 2021](https://www.youtube.com/watch?v=LtaWPe2sgRY&t=1s) (November 24th 2021, in Polish, ~34 minutes, technical presentation with details about the GSM package)
|
||||
- ["A BasePlus Package for SAS" - SAS Explore 2022](https://communities.sas.com/t5/SAS-Explore-Presentations/A-BasePlus-Package-for-SAS/ta-p/838246 "SASexplore2022 communities.sas.com") (September 27th-29th 2022, ~28 minutes, technical presentation with details about the BasePlus package), alternative video at YouTube is [here](https://www.youtube.com/watch?v=-Poxkx5WfOQ "SASexplore2022 TouTube")
|
||||
- ["SAS Packages - State of the Union" - SaSensei International Dojo No. 13](https://www.youtube.com/watch?v=1GEldZYQjj0&t=0s "SID no. 13") (November 10th 2022, ~50 minutes, general overview with the latest technical details)
|
||||
- ["SAS Packages Framework - an easy code sharing medium for SAS" - Warsaw IT Days 2023](https://youtu.be/T52Omisi0dk&t=0s "Warsaw IT Days 2023") (March 31st 2023, ~60 minutes, general overview with technical details for user and developer)
|
||||
|
||||
|
||||
### Tutorials:
|
||||
|
||||
Here are links to some tutorials which may help you to start with the framework.
|
||||
Order is dictated by the amount of details presented.
|
||||
Letter "D" indicates tutorial dedicated for developers and "U" materials for users.
|
||||
|
||||
1) (DU) The latest [video](https://youtu.be/T52Omisi0dk&t=0s) explaining the idea.
|
||||
|
||||
2) (D) Very simple ["Hello World" example](https://github.com/yabwon/SAS_PACKAGES/blob/main/SPF/Documentation/HelloWorldPackage.md) tutorial for developers. As a support a [walk-through video](https://youtu.be/T52Omisi0dk&t=2160s)
|
||||
|
||||
3) (D) Article and all required materials for ["My first SAS Package"](https://github.com/yabwon/SAS_PACKAGES/tree/main/SPF/Documentation/Paper_1079-2021) tutorial.
|
||||
|
||||
4) (DU) Materials from Hands-on-Workshop (4+ hours) tutorial: [Share your code with SAS Packages](https://github.com/yabwon/HoW-SASPackages).
|
||||
|
||||
|
||||
---
|
||||
|
||||
### Initiative to add SAS Packages Framework to SAS Base/Viya:
|
||||
|
||||
A **SASware Ballot Idea** for adding *SAS Packages Framework* macros into Base SAS and Viya was submitted Friday, May 27th 2022. If you would like to support the idea visit this [communities.sas.com post](https://communities.sas.com/t5/SASware-Ballot-Ideas/Add-SAS-Packages-Framework-to-the-SAS-Base-Viya/idi-p/815508) and up vote the idea!
|
||||
|
||||
---
|
||||
|
||||
### The User:
|
||||
To use a package:
|
||||
- Create a folder for your packages, under Windows OS family, e.g. `C:/SAS_PACKAGES` or under Linux/UNIX OS family, e.g. `/home/<username>/SAS_PACKAGES`.
|
||||
|
||||
and then either:
|
||||
The first step to use a package with the SAS Packages Framework:
|
||||
|
||||
- Download the `SPFinit.sas` file (the SAS Packages Framework) into the local packages folder.
|
||||
- Create a folder for your packages, under Windows OS family e.g., `C:/SAS_PACKAGES` or under Linux/UNIX OS family e.g., `/home/<username>/SAS_PACKAGES`.
|
||||
|
||||
Then either:
|
||||
|
||||
- Manually download the `SPFinit.sas` file (the SAS Packages Framework) into the local packages folder.
|
||||
- \[Optional\] Manually download the `<packageName>.zip` file into the local packages folder.
|
||||
- and Execute:
|
||||
```
|
||||
filename packages "<directory/containing/packages/>"; /* setup directory for packages */
|
||||
%include packages(SPFinit.sas); /* enable the framework */
|
||||
|
||||
/* %installPackage(packageName) */ /* install the package, unless you downloaded it manually */
|
||||
```sas
|
||||
filename packages "<directory/containing/packages/>"; /* setup directory for packages */
|
||||
%include packages(SPFinit.sas); /* enable the framework */
|
||||
|
||||
%helpPackage(packageName) /* get help about the package */
|
||||
%loadPackage(packageName) /* load the package content into the SAS session */
|
||||
/* %installPackage(packageName) */ /* install the package, unless you downloaded it manually */
|
||||
|
||||
%helpPackage(packageName) /* get help about the package */
|
||||
%loadPackage(packageName) /* load the package content into the SAS session */
|
||||
```
|
||||
|
||||
or if you need it just for "one time" only Execute:
|
||||
or if you need it just for "one time" only:
|
||||
|
||||
```
|
||||
filename packages "%sysfunc(pathname(work))"; /* setup temporary directory for packages in the WORK */
|
||||
- Execute:
|
||||
|
||||
```sas
|
||||
filename packages "%sysfunc(pathname(work))"; /* setup WORK as temporary directory for packages */
|
||||
filename SPFinit url "https://raw.githubusercontent.com/yabwon/SAS_PACKAGES/main/SPF/SPFinit.sas";
|
||||
%include SPFinit; /* enable the framework */
|
||||
|
||||
%installPackage(packageName) /* install the package */
|
||||
%installPackage(packageName) /* install a package */
|
||||
%helpPackage(packageName) /* get help about the package */
|
||||
%loadPackage(packageName) /* load the package content into the SAS session */
|
||||
```
|
||||
|
||||
[**Workshop video for the User**](https://youtu.be/qX_-HJ76g8Y)\[May 6th, 2020\] [a bit outdated but gives the idea how it works]
|
||||
|
||||
or do it pragmatically:
|
||||
|
||||
- Enable the framework [first time only]:
|
||||
|
||||
```sas
|
||||
filename SPFinit url "https://raw.githubusercontent.com/yabwon/SAS_PACKAGES/main/SPF/SPFinit.sas";
|
||||
%include SPFinit; /* enable the framework */
|
||||
```
|
||||
|
||||
or (shorter) with:
|
||||
|
||||
```sas
|
||||
filename SPFinit url "https://bit.ly/SPFinit";
|
||||
%include SPFinit; /* enable the framework */
|
||||
```
|
||||
|
||||
- Install the framework on your machine in the folder you created:
|
||||
|
||||
```sas
|
||||
filename packages "<directory/containing/packages/>";
|
||||
%installPackage(SPFinit) /* install the framework */
|
||||
```
|
||||
|
||||
- From now on run it like this:
|
||||
|
||||
```sas
|
||||
filename packages "<directory/containing/packages/>";
|
||||
%include packages(SPFinit.sas);
|
||||
|
||||
%installPackage(packageName) /* install a package */
|
||||
%helpPackage(packageName) /* get help about the package */
|
||||
%loadPackage(packageName) /* load the package content into the SAS session */
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
The "Workshop video for the User" got outdated (in general). Newer version is coming soon, in the mean time see some of the videos from the "Recordings and Presentations" section above.
|
||||
(You can watch the workshop if you wish, link is working and some parts are still valid source of information e.g., "`ICE` loading" or "`disk` loading")
|
||||
|
||||
<s>[**Workshop video for the User**](https://youtu.be/qX_-HJ76g8Y) \[May 6th, 2020\] [~86 minutes, outdated (installPackage macro was not there yet) but gives the idea how it works especially load, help, unload, ICEload, and other details]</s>
|
||||
|
||||
---
|
||||
|
||||
### The Developer:
|
||||
|
||||
To create your own package:
|
||||
- Read the [**`SAS(r) packages - the way to share (a how to)- Paper 4725-2020 - extended.pdf`**](https://github.com/yabwon/SAS_PACKAGES/blob/main/SPF/Documentation/SAS(r)%20packages%20-%20the%20way%20to%20share%20(a%20how%20to)-%20Paper%204725-2020%20-%20extended.pdf "SAS packages - the way to share") to learn more details.
|
||||
- Download and use the `SPFinit.sas` file (the SAS Packages Framework), the part of the framework required for *testing* is there too.
|
||||
|
||||
#### If you have any questions, suggestions, or ideas do not hesitate to contact me!
|
||||
- Download (and use) the `SPFinit.sas` file (the SAS Packages Framework), the part of the framework required for *testing* is there too.
|
||||
|
||||
- See this ["Hello World" example tutorial.](https://github.com/yabwon/SAS_PACKAGES/blob/main/SPF/Documentation/HelloWorldPackage.md "Hello World")
|
||||
|
||||
- Read the [**`SAS Packages - The Way to Share (a How-To) - Paper 4725-2020 - extended version`**](https://github.com/yabwon/SAS_PACKAGES/blob/main/SPF/Documentation/SAS(r)%20packages%20-%20the%20way%20to%20share%20(a%20how%20to)-%20Paper%204725-2020%20-%20extended.pdf "SAS packages - the way to share") article to learn more details.
|
||||
|
||||
- Read the **`My First SAS Package: A How-To - Paper 1079-2021`** article available at communities.sas.com [**`here`**](https://communities.sas.com/t5/SAS-Global-Forum-Proceedings/My-First-SAS-Package-A-How-To/ta-p/726319 "My First SAS Package: A How-To") or locally [**`here`**](https://github.com/yabwon/SAS_PACKAGES/blob/main/SPF/Documentation/Paper_1079-2021/My%20First%20SAS%20Package%20-%20a%20How%20To.pdf "My First SAS Package: A How-To")
|
||||
|
||||
The SAS Packages Framework [(short) documentation](https://github.com/yabwon/SAS_PACKAGES/blob/main/SPF/SPFinit.md) to quickly see macros options and parameters.
|
||||
|
||||
---
|
||||
|
||||
### If you have any questions, suggestions, or ideas do not hesitate to contact me!
|
||||
|
||||
---
|
||||
|
||||
### Updates worth mentioning:
|
||||
|
||||
**Update**\[December 10th, 2023\]**:** `markdownDoc=` **parameter added to** `%generatePackage()` **macro, which allows to generate markdown file with documentation. Content is taken from the help information notes and the description. (see [here](https://github.com/yabwon/SAS_PACKAGES/releases/tag/20231210 "markdown documentation"))**.
|
||||
|
||||
**Update**\[November 11th, 2023\]**:** `KMFSNIP` **type for *key macro abbreviations* snippets added to the framework. (see [here](https://github.com/yabwon/SAS_PACKAGES/releases/tag/20231111 "KMF-abbreviations"))**.
|
||||
|
||||
**Update**\[February 7th, 2023\]**:** `ADDCNT` **type for *additional content* feature and ** `%loadPackageAddCnt()` **macro added to the framework. (see [here](https://github.com/yabwon/SAS_PACKAGES/releases/tag/20230207 "Additional Content"))**.
|
||||
|
||||
**Update**\[December 12th, 2022\]**:** `CASLUDF` **type for CASL user defined functions added to the framework. Utility macros for for loading content in proc IML and proc CAS added. (see [here](https://github.com/yabwon/SAS_PACKAGES/releases/tag/20221212 "New Type and Utility macros"))**.
|
||||
|
||||
**Update**\[November 21st, 2022\]**:** `%loadPackage()` **macro allows Cherry Picking of content (see [here](https://github.com/yabwon/SAS_PACKAGES/releases/tag/20221121 "Cherry Picking"))**.
|
||||
|
||||
**Update**\[September 30th, 2022\]**:** **New dedicated repository:** *SASPAC - the SAS Packages Archive* **is available as new location for packages storage**. Location of SASPAC is: [`https://github.com/SASPAC`](https://github.com/SASPAC)
|
||||
|
||||
**Update**\[November 11th, 2021\]**:** `%extendPackagesFileref()` **macro is available**.
|
||||
|
||||
**Update**\[October 15th, 2020\]**:** `%previewPackage()` **macro is available**.
|
||||
|
||||
**Update**\[September 11th, 2020\]**:** ` %loadPackageS()` and `%verifyPackage()` **macros are available**.
|
||||
|
||||
**Update**\[June 3rd, 2020\]**:** `%installPackage()` **macro is available**. The `%installPackage()` macro is embedded in the `loadpackage.sas` part of the framework.
|
||||
|
||||
**Update**\[June 10th, 2020\]**:** To see help info about framework macros and their parameters just run: `%generatePackage()`, `%installPackage()`, `%helpPackage()`, `%loadPackage()`, and `%unloadPackage()` with empty parameter list.
|
||||
|
||||
**Update**\[July 30th, 2020\]**:** All components of SAS Packages Framework are now in one file `SPFinit.sas` (located in the `./SPF` directory). Documentation moved to `./SPF/Documentation` directory. Packages zip files moved to `./packages` directory.
|
||||
|
||||
## Where the SAS Packages Framework is used:
|
||||
This is a list of locations where the SAS Packages Framework is used. If you want to share that you are using SPF let me know and I'll update the list.
|
||||
**Update**\[June 10th, 2020\]**:** To see help info about framework macros and their parameters just run: `%generatePackage()`, `%installPackage()`, `%helpPackage()`, `%loadPackage()`, and `%unloadPackage()` with empty parameter list.
|
||||
|
||||
The List:
|
||||
- Europe
|
||||
- Poland
|
||||
- Warsaw
|
||||
**Update**\[June 3rd, 2020\]**:** `%installPackage()` **macro is available**. The `%installPackage()` macro is embedded in the `loadpackage.sas` part of the framework.
|
||||
|
||||
---
|
||||
|
||||
## Where the SAS Packages Framework is used:
|
||||
This is a list of locations where the SAS Packages Framework is used:
|
||||
- Warsaw (Poland)
|
||||
|
||||
If you want to share that you are using the SPF let me know and I'll update the list.
|
||||
|
||||
If you find the SPF useful **share info** about it or **give it a [star (:star:)](https://github.com/yabwon/SAS_PACKAGES/stargazers)** so more people will know.
|
||||
|
||||
---
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
## Available packages:
|
||||
Currently the following packages are available (see the `./packages` directory):
|
||||
|
||||
- **SQLinDS**\[2.2\], based on Mike Rhoads' article *Use the Full Power of SAS in Your Function-Style Macros*. The package allows to write SQL queries in the data step, e.g.
|
||||
```
|
||||
data class;
|
||||
set %SQL(select * from sashelp.class order by age);
|
||||
run;
|
||||
```
|
||||
SHA256 digest for SQLinDS: CE1A266B9030E5E336B45F53DF483F6913FD8AE88A2884CEE88BEEF621FDBD78
|
||||
This section presents some examples of available SAS packages.
|
||||
|
||||
[Documentation for SQLinDS](https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/sqlinds.md "Documentation for SQLinDS")
|
||||
**(!)** Since *September 2022* the default and **official** location for packages is **SASPAC - the SAS Packages Archive** located under: [`https://github.com/SASPAC`](https://github.com/SASPAC) where each package is stored as a separate repository with historical versions.
|
||||
|
||||
- **MacroCore**\[1\], a macro library for SAS application developers. Over 100 macros for Base SAS, metadata, and Viya. Provided by the [SASjs framework](https://sasjs.io "SASjs framework").
|
||||
**(!)** For "backward compatibility"/historical point of view the following packages are also available under the `./packages` directory in this repository.
|
||||
|
||||
SHA256 digest for MacroCore: A23C29529F3CE7D0C8BEE9545C5D22D5B5594907547374A5135B8E5A48D7687B
|
||||
Packages:
|
||||
|
||||
[Documentation for MacroCore](https://core.sasjs.io "Documentation for MacroCore")
|
||||
- **SQLinDS**
|
||||
|
||||
- **DFA** (Dynamic Function Arrays)\[0.2\], contains set of macros and FCMP functions which implement: a dynamically allocated array, a stack, a fifo queue, an ordered stack, and a priority queue, run `%helpPackage(DFA,createDFArray)` to find examples.
|
||||
[Documentation for SQLinDS](https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/sqlinds.md "Documentation for SQLinDS")
|
||||
|
||||
SHA256 digest for DFA: C795736F55B3C6EFBEF2E82362694EB017D37C54E6AEC3EB0F6F813F69F54B5F
|
||||
[SQLinDS in SASPAC](https://github.com/SASPAC/sqlinds "SQLinDS in SASPAC")
|
||||
|
||||
|
||||
- **macroArray**\[0.7\], implementation of an array concept in a macrolanguage, e.g.
|
||||
```
|
||||
%array(ABC[17] (111:127), macarray=Y);
|
||||
|
||||
%macro test();
|
||||
%do i = 1 %to 17;
|
||||
%put &i.) %ABC(&i.);
|
||||
%end;
|
||||
%mend;
|
||||
%test()
|
||||
|
||||
%let %ABC(13,i) = 99999; /* i = insert */
|
||||
- **DFA** (Dynamic Function Arrays)
|
||||
|
||||
%do_over(ABC, phrase=%nrstr(
|
||||
%put &_i_.%) %ABC(&_i_.);
|
||||
),
|
||||
which = 1:H:2
|
||||
);
|
||||
```
|
||||
SHA256 digest for macroArray: 0F1B985E2FC34C91D2A3BD237DC294502A76913B71266D76702A5E77A78C9CA7
|
||||
[Documentation for DFA](https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/dfa.md "Documentation for DFA")
|
||||
|
||||
[Documentation for macroArray](https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/macroarray.md "Documentation for macroArray")
|
||||
[DFA in SASPAC](https://github.com/SASPAC/dfa "DFA in SASPAC")
|
||||
|
||||
- **macroArray**
|
||||
|
||||
[Documentation for macroArray](https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/macroarray.md "Documentation for macroArray")
|
||||
|
||||
[MacroArray in SASPAC](https://github.com/SASPAC/macroarray "MacroArray in SASPAC")
|
||||
|
||||
- **BasePlus**
|
||||
|
||||
[Documentation for BasePlus](https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/baseplus.md "Documentation for BasePlus")
|
||||
|
||||
[BasePlus in SASPAC](https://github.com/SASPAC/baseplus "BasePlus in SASPAC")
|
||||
|
||||
- **GSM** (Generate Secure Macros)
|
||||
|
||||
[Documentation for GSM](https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/gsm.md "Documentation for GSM")
|
||||
|
||||
[GSM in SASPAC](https://github.com/SASPAC/gsm "GSM in SASPAC")
|
||||
|
||||
- **dynMacroArray**
|
||||
|
||||
Development of this package is currently on hold.
|
||||
|
||||
|
||||
- **BasePlus**\[0.9\] adds a bunch of functionalities I am missing in BASE SAS, such as:
|
||||
```
|
||||
call arrMissToRight(myArray);
|
||||
call arrFillMiss(17, myArray);
|
||||
call arrFill(42, myArray);
|
||||
|
||||
rc = delDataset("DataSetToDrop");
|
||||
|
||||
string = catXFn("date9.", "#", myArray);
|
||||
|
||||
format x bool.;
|
||||
|
||||
%put %getVars(sashelp.class, pattern = ght$, sep = +, varRange = _numeric_);
|
||||
```
|
||||
SHA256 digest for BasePlus: B25A3992B6FCD13528BEE462B3ADD0F5A6D15E607A6DABAA984CA66B0AD69415
|
||||
|
||||
[Documentation for BasePlus](https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/baseplus.md "Documentation for BasePlus")
|
||||
|
||||
- **dynMacroArray**\[0.2\], set of macros (wrappers for a hash table) emulating dynamic array in the data step (macro predecessor of DFA)
|
||||
|
||||
SHA256 digest for dynMacroArray: 5E8CCC88CC048A0B564CEE37C6CF4013857D9CFF3FA1B6B9AD6F719D08B30005
|
||||
|
||||
### ======
|
||||
|
||||
Binary file not shown.
156
SPF/Documentation/HelloWorldPackage.md
Normal file
156
SPF/Documentation/HelloWorldPackage.md
Normal file
@@ -0,0 +1,156 @@
|
||||
|
||||
## The "Hello World" Package
|
||||
|
||||
---
|
||||
|
||||
This is a "Hello World" example on how to build your first package with help of the SAS Packages Framework.
|
||||
|
||||
We will generate a `HelloWorld` package.
|
||||
|
||||
Follow the step by step instruction below.
|
||||
|
||||
---
|
||||
|
||||
`Step 1.` Create a folder for the framework e.g.,
|
||||
`/home/<myUserName>/SASpackages` or `C:/SASpackages`
|
||||
|
||||
`Step 2.` Run the following code to install The SAS Packages Framework
|
||||
in the folder you created in the `Step 1.`
|
||||
|
||||
```sas
|
||||
filename packages "<put/folder/from/the/step/one/here>";
|
||||
filename SPFinit url "https://raw.githubusercontent.com/yabwon/SAS_PACKAGES/main/SPF/SPFinit.sas";
|
||||
%include SPFinit;
|
||||
%installPackage(SPFinit)
|
||||
```
|
||||
|
||||
Check out the *log* to verify if the `Step 2.` was successful.
|
||||
If it was - then continue.
|
||||
|
||||
|
||||
`Step 3.` Create a folder for the content of the package we will generate e.g.,
|
||||
`/home/<myUserName>/HelloWorldPackage` or `C:/HelloWorldPackage`
|
||||
|
||||
`Step 4.` Inside the directory from the `Step 3.` create two sub-folders: `01_formats`
|
||||
and `02_macros`. Remember to use *lower case letters* only!
|
||||
|
||||
`Step 5.` Inside the `01_formats` folder create a `helloworldformat.sas` file.
|
||||
Remember to use lower case letters in the file name. Copy-paste below code
|
||||
into that file:
|
||||
|
||||
```sas
|
||||
/*** HELP START ***//*
|
||||
This is a help info for the `HelloWorldFormat.` format.
|
||||
|
||||
Category *other* is marked with exclamation mark (`!`).
|
||||
*//*** HELP END ***/
|
||||
|
||||
value HelloWorldFormat
|
||||
1 = " Hello"
|
||||
2 = " SAS"
|
||||
3 = " Packages"
|
||||
4 = " World"
|
||||
other = "!"
|
||||
;
|
||||
```
|
||||
|
||||
`Step 6.` Inside the `02_macros` folder create a `helloworldmacro.sas` file.
|
||||
Remember to use lower case letters in the file name. Copy-paste below code
|
||||
into that file:
|
||||
```sas
|
||||
/*** HELP START ***//*
|
||||
This is a help info for the `%helloWorldMacro()` macro.
|
||||
|
||||
Macro has the following parameter(s):
|
||||
- `n` - *Required*, provides number of loop iterations.
|
||||
|
||||
*//*** HELP END ***/
|
||||
|
||||
%macro HelloWorldMacro(n);
|
||||
data _null_;
|
||||
do i = 1 to &n.;
|
||||
put i HelloWorldFormat. @;
|
||||
end;
|
||||
run;
|
||||
%mend HelloWorldMacro;
|
||||
```
|
||||
|
||||
|
||||
`Step 7.` Inside the directory from the `Step 3.` create a `description.sas` file.
|
||||
Remember to use lower case letters in the file name. Copy-paste below text
|
||||
into that file, adjust lines 5 and 6:
|
||||
```txt
|
||||
Type: Package
|
||||
Package: helloWorld
|
||||
Title: My Hello World SAS package.
|
||||
Version: 1.0
|
||||
Author: <myFirstname> <myLastname> (my@mail.com)
|
||||
Maintainer: <myFirstname> <myLastname> (my@mail.com)
|
||||
License: MIT
|
||||
Encoding: UTF8
|
||||
|
||||
Required: "Base SAS Software"
|
||||
|
||||
DESCRIPTION START:
|
||||
### My "Hello World" SAS package ###
|
||||
|
||||
The "Hello World" is my first SAS package and
|
||||
for sure it will not be the last package one!
|
||||
|
||||
Using packages is a good idea!
|
||||
DESCRIPTION END:
|
||||
```
|
||||
|
||||
`Step 8.` Execute the following code and check the log
|
||||
to read the `%generatePackage()` macro help info.
|
||||
|
||||
```sas
|
||||
%generatePackage()
|
||||
```
|
||||
|
||||
`Step 9.` Execute the following code using the folder
|
||||
from the `Step 3.` and check the log to see how
|
||||
the process of package generation went.
|
||||
|
||||
```sas
|
||||
%generatePackage(
|
||||
filesLocation=<put/folder/from/the/step/three/here>
|
||||
,markdownDoc=1
|
||||
)
|
||||
```
|
||||
|
||||
`Step 10.` See the information in the output window and in the log.
|
||||
The `WARNING:[License] No license.sas file provided, default (MIT) licence file will be generated.` can be ignored.
|
||||
|
||||
`Step 11.` Check the directory from the `Step 3.` and look for the `helloworld.zip` package file and `helloworld.md` documentation file.
|
||||
|
||||
---
|
||||
|
||||
`Step 12.` Start a new SAS session, run the following code, and investigate the log:
|
||||
|
||||
```sas
|
||||
filename packages ("<put/folder/from/the/step/one/here>" "<put/folder/from/the/step/three/here>");
|
||||
%include packages(SPFinit.sas);
|
||||
|
||||
%loadPackage(HelloWorld)
|
||||
|
||||
%HelloWorldMacro(7)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Congratulations!! You've just created your first HelloWorld package.
|
||||
|
||||
Now you are ready to do smome more advanced work.
|
||||
|
||||
- Read the **`My First SAS Package: A How-To - Paper 1079-2021`** article, available at communities.sas.com [**`here`**](https://communities.sas.com/t5/SAS-Global-Forum-Proceedings/My-First-SAS-Package-A-How-To/ta-p/726319 "My First SAS Package: A How-To + Video") (video included) or locally [**`here`**](https://github.com/yabwon/SAS_PACKAGES/blob/main/SPF/Documentation/Paper_1079-2021/My%20First%20SAS%20Package%20-%20a%20How%20To.pdf "My First SAS Package: A How-To"), describing the proces of a package creation with more advanced example and technical details.
|
||||
|
||||
- Go to "bare metal" and read the [**`SAS Packages - The Way to Share (a How-To) - Paper 4725-2020 - extended version`**](https://github.com/yabwon/SAS_PACKAGES/blob/main/SPF/Documentation/SAS(r)%20packages%20-%20the%20way%20to%20share%20(a%20how%20to)-%20Paper%204725-2020%20-%20extended.pdf "SAS packages - the way to share") - an article which contains all technical details on how the SAS Packages Framework works and how to use it (both as a develope and as a user).
|
||||
|
||||
---
|
||||
|
||||
The SAS Packages Framework [(short) documetation](https://github.com/yabwon/SAS_PACKAGES/blob/main/SPF/SPFinit.md) to quickly see macros options and parametera.
|
||||
|
||||
---
|
||||
|
||||
|
||||
Binary file not shown.
80
SPF/Documentation/Paper_1079-2021/Paper_1079-2021.sas
Normal file
80
SPF/Documentation/Paper_1079-2021/Paper_1079-2021.sas
Normal file
@@ -0,0 +1,80 @@
|
||||
/*one library "myLib" created in the (same named) subderectory of the "WORK" directory.*/
|
||||
data _null_;
|
||||
length rc0 $ 32767 rc1 rc2 8;
|
||||
lib = "myLib";
|
||||
rc0 = DCREATE(lib, "%sysfunc(pathname(work))/");
|
||||
put rc0 = ;
|
||||
rc1 = LIBNAME(lib, "%sysfunc(pathname(work))/" !! lib, "BASE");
|
||||
rc2 = LIBREF (lib);
|
||||
if rc2 NE 0 then
|
||||
rc1 = LIBNAME(lib, "%sysfunc(pathname(work))", "BASE");
|
||||
run;
|
||||
|
||||
libname myLib LIST;
|
||||
|
||||
/*two FCMP functions: "F1" and "F2", */
|
||||
proc FCMP outlib = work.f.p;
|
||||
function F1(n);
|
||||
return (n+1);
|
||||
endsub;
|
||||
|
||||
function F2(n);
|
||||
return (n+2);
|
||||
endsub;
|
||||
run;
|
||||
options cmplib = work.f;
|
||||
|
||||
/*one numeric format "fmtNum" and informat "infNum", */
|
||||
proc FORMAT;
|
||||
value fmtNum
|
||||
low -< 0 = "negative"
|
||||
0 = "zero"
|
||||
0 <- high = "positive"
|
||||
other = "missing"
|
||||
;
|
||||
invalue infNum
|
||||
"negative" = -1
|
||||
"zero" = 0
|
||||
"positive" = 1
|
||||
"missing" = .
|
||||
other = 42
|
||||
;
|
||||
run;
|
||||
|
||||
/*one exemplary small dataset "myLib.smallDataset", and*/
|
||||
data myLib.smallDataset;
|
||||
do n = ., -1, 0, 1;
|
||||
m = put(n, fmtNum.);
|
||||
output;
|
||||
end;
|
||||
run;
|
||||
|
||||
/*one exemplary bigger dataset "myLib.biggerDataset".*/
|
||||
data myLib.biggerDataset;
|
||||
do i = ., -1e6 to 1e6;
|
||||
j = put(i, fmtNum.);
|
||||
k = ranuni(17);
|
||||
output;
|
||||
end;
|
||||
run;
|
||||
|
||||
/*two macros: "mcrOne" and "mcrTwo" */
|
||||
%macro mcrOne();
|
||||
%put **Hi! This is macro &sysmacroname.**;
|
||||
data _null_;
|
||||
set myLib.smallDataset;
|
||||
p = f1(n);
|
||||
p + f2(n);
|
||||
put (n p) (= fmtNum.);
|
||||
run;
|
||||
%mend mcrOne;
|
||||
|
||||
%macro mcrTwo(m=mcrOne);
|
||||
%put **This is macro &sysmacroname.**;
|
||||
%put **and I am calling the &m.**;
|
||||
%&m.()
|
||||
|
||||
%put The answer is: %sysfunc(inputn("I don't know...", infNum.));
|
||||
%mend mcrTwo;
|
||||
|
||||
/* %mcrTwo() */
|
||||
4
SPF/Documentation/Paper_1079-2021/generate_package.sas
Normal file
4
SPF/Documentation/Paper_1079-2021/generate_package.sas
Normal file
@@ -0,0 +1,4 @@
|
||||
filename packages "~/saspackages";
|
||||
%include packages(SPFinit.sas);
|
||||
|
||||
%generatePackage(~/saspackages/myPackage)
|
||||
@@ -0,0 +1,7 @@
|
||||
filename packages "~/saspackages";
|
||||
|
||||
filename SPFinit url
|
||||
"https://raw.githubusercontent.com/yabwon/SAS_PACKAGES/main/SPF/SPFinit.sas";
|
||||
%include SPFinit;
|
||||
|
||||
%installPackage(SPFinit)
|
||||
@@ -0,0 +1,18 @@
|
||||
/*** HELP START ***/
|
||||
/*
|
||||
`myLib` library
|
||||
*/
|
||||
/*** HELP END ***/
|
||||
|
||||
data _null_;
|
||||
length rc0 $ 32767 rc1 rc2 8;
|
||||
lib = "myLib";
|
||||
rc0 = DCREATE(lib, "%sysfunc(pathname(work))/");
|
||||
put rc0 = ;
|
||||
rc1 = LIBNAME(lib, "%sysfunc(pathname(work))/" !! lib, "BASE");
|
||||
rc2 = LIBREF (lib);
|
||||
if rc2 NE 0 then
|
||||
rc1 = LIBNAME(lib, "%sysfunc(pathname(work))", "BASE");
|
||||
run;
|
||||
|
||||
libname myLib LIST;
|
||||
@@ -0,0 +1,9 @@
|
||||
/*** HELP START ***/
|
||||
/*
|
||||
`F1` function
|
||||
*/
|
||||
/*** HELP END ***/
|
||||
|
||||
function F1(n);
|
||||
return (n+1);
|
||||
endsub;
|
||||
@@ -0,0 +1,9 @@
|
||||
/*** HELP START ***/
|
||||
/*
|
||||
`F2` function
|
||||
*/
|
||||
/*** HELP END ***/
|
||||
|
||||
function F2(n);
|
||||
return (n+2);
|
||||
endsub;
|
||||
@@ -0,0 +1,12 @@
|
||||
/*** HELP START ***/
|
||||
/*
|
||||
`fmtNum` format
|
||||
*/
|
||||
/*** HELP END ***/
|
||||
|
||||
value fmtNum
|
||||
low -< 0 = "negative"
|
||||
0 = "zero"
|
||||
0 <- high = "positive"
|
||||
other = "missing"
|
||||
;
|
||||
@@ -0,0 +1,13 @@
|
||||
/*** HELP START ***/
|
||||
/*
|
||||
`infNum` informat
|
||||
*/
|
||||
/*** HELP END ***/
|
||||
|
||||
invalue infNum
|
||||
"negative" = -1
|
||||
"zero" = 0
|
||||
"positive" = 1
|
||||
"missing" = .
|
||||
other = 42
|
||||
;
|
||||
@@ -0,0 +1,12 @@
|
||||
/*** HELP START ***/
|
||||
/*
|
||||
`myLib.smallDataset` data
|
||||
*/
|
||||
/*** HELP END ***/
|
||||
|
||||
data myLib.smallDataset;
|
||||
do n = ., -1, 0, 1;
|
||||
m = put(n, fmtNum.);
|
||||
output;
|
||||
end;
|
||||
run;
|
||||
@@ -0,0 +1,13 @@
|
||||
/*** HELP START ***/
|
||||
/*
|
||||
`myLib.biggerDataset` data
|
||||
*/
|
||||
/*** HELP END ***/
|
||||
|
||||
data myLib.biggerDataset;
|
||||
do i = ., -1e6 to 1e6;
|
||||
j = put(i, fmtNum.);
|
||||
k = ranuni(17);
|
||||
output;
|
||||
end;
|
||||
run;
|
||||
@@ -0,0 +1,15 @@
|
||||
/*** HELP START ***/
|
||||
/*
|
||||
`mcrOne` macro
|
||||
*/
|
||||
/*** HELP END ***/
|
||||
|
||||
%macro mcrOne();
|
||||
%put **Hi! This is macro &sysmacroname.**;
|
||||
data _null_;
|
||||
set myLib.smallDataset;
|
||||
p = f1(n);
|
||||
p + f2(n);
|
||||
put (n p) (= fmtNum.);
|
||||
run;
|
||||
%mend mcrOne;
|
||||
@@ -0,0 +1,30 @@
|
||||
/*** HELP START ***/
|
||||
/*
|
||||
## General Info: ##
|
||||
|
||||
The `%mcrTwo()` macro is the main macro of the package.
|
||||
|
||||
It has one key-value parameter `m` with default value `mcrOne`.
|
||||
*/
|
||||
/*** HELP END ***/
|
||||
|
||||
%macro mcrTwo(m=mcrOne);
|
||||
%put **This is macro &sysmacroname.**;
|
||||
%put **and I am calling the &m.**;
|
||||
%&m.()
|
||||
|
||||
%put The answer is: %sysfunc(inputn("I don't know...", infNum.));
|
||||
%mend mcrTwo;
|
||||
|
||||
/*** HELP START ***/
|
||||
/*
|
||||
## Examples: ##
|
||||
|
||||
Example 1. Basic use-case:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
%mcrTwo(m=mcrOne)
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
*/
|
||||
/*** HELP END ***/
|
||||
21
SPF/Documentation/Paper_1079-2021/myPackage/description.sas
Normal file
21
SPF/Documentation/Paper_1079-2021/myPackage/description.sas
Normal file
@@ -0,0 +1,21 @@
|
||||
Type: Package
|
||||
Package: myPackage
|
||||
Title: My first SAS package.
|
||||
Version: 1.0
|
||||
Author: John Smith (john.smith@mail.com)
|
||||
Maintainer: Jane Smith (jane.smith@mail.com)
|
||||
License: MIT
|
||||
Encoding: UTF8
|
||||
|
||||
Required: "Base SAS Software"
|
||||
|
||||
DESCRIPTION START:
|
||||
## The myPackage ##
|
||||
|
||||
The `myPackage` is my first SAS package and
|
||||
for sure it won't be the last package!
|
||||
It was created during SAS Global Forum 2021
|
||||
virtual event.
|
||||
|
||||
It helps me to share my code with other SAS users!
|
||||
DESCRIPTION END:
|
||||
@@ -0,0 +1,2 @@
|
||||
|
||||
%mcrTwo(m=mcrOne)
|
||||
14
SPF/Documentation/Paper_1079-2021/mypackage.md
Normal file
14
SPF/Documentation/Paper_1079-2021/mypackage.md
Normal file
@@ -0,0 +1,14 @@
|
||||
## General Info: ##
|
||||
|
||||
The `%mcrTwo()` macro is the main macro of the package.
|
||||
|
||||
It has one key-value parameter `m` with default value `mcrOne`.
|
||||
|
||||
## Examples: ##
|
||||
|
||||
Example 1. Basic use-case:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
%mcrTwo(m=mcrOne)
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Binary file not shown.
104
SPF/Macros/extendpackagesfileref.sas
Normal file
104
SPF/Macros/extendpackagesfileref.sas
Normal file
@@ -0,0 +1,104 @@
|
||||
/*+extendPackagesFileref+*/
|
||||
/*** HELP START ***/
|
||||
|
||||
%macro extendPackagesFileref(
|
||||
packages /* A valid fileref name,
|
||||
when empty the "packages" value is used */
|
||||
)/secure
|
||||
/*** HELP END ***/
|
||||
des = 'Macro to list directories pointed by "packages" fileref, version 20231210. Run %extendPackagesFileref(HELP) for help info.'
|
||||
;
|
||||
|
||||
%if %QUPCASE(&packages.) = HELP %then
|
||||
%do;
|
||||
%local options_tmp ;
|
||||
%let options_tmp = ls=%sysfunc(getoption(ls))ps=%sysfunc(getoption(ps))
|
||||
%sysfunc(getoption(notes)) %sysfunc(getoption(source))
|
||||
msglevel=%sysfunc(getoption(msglevel))
|
||||
;
|
||||
options NOnotes NOsource ls=MAX ps=MAX msglevel=N;
|
||||
%put ;
|
||||
%put ###########################################################################################;
|
||||
%put ### This is short help information for the `extendPackagesFileref` macro #;
|
||||
%put #-----------------------------------------------------------------------------------------#;;
|
||||
%put # #;
|
||||
%put # Macro to list directories pointed by 'packages' fileref, version `20231210` #;
|
||||
%put # #;
|
||||
%put # A SAS package is a zip file containing a group #;
|
||||
%put # of SAS codes (macros, functions, data steps generating #;
|
||||
%put # data, etc.) wrapped up together and embedded inside the zip. #;
|
||||
%put # #;
|
||||
%put # The `%nrstr(%%extendPackagesFileref())` macro lists directories pointed by #;
|
||||
%put # the packages fileref. It allows to add new directories to packages folder list. #;
|
||||
%put # #;
|
||||
%put #### Parameters: #;
|
||||
%put # #;
|
||||
%put # 1. `packages` *Optional.* A valid fileref name, when empty the "packages" is used. #;
|
||||
%put # Use case: #;
|
||||
%put # `%nrstr(%%extendPackagesFileref()).` #;
|
||||
%put # #;
|
||||
%put # When used as: `%nrstr(%%extendPackagesFileref(HELP))` it displays this help information. #;
|
||||
%put # #;
|
||||
%put #-----------------------------------------------------------------------------------------#;
|
||||
%put # #;
|
||||
%put # Visit: `https://github.com/yabwon/SAS_PACKAGES/tree/main/SPF/Documentation` #;
|
||||
%put # to learn more. #;
|
||||
%put # #;
|
||||
%put #### Example ##############################################################################;
|
||||
%put # #;
|
||||
%put # Enabling the SAS Package Framework #;
|
||||
%put # from the local directory and adding #;
|
||||
%put # new directory. #;
|
||||
%put # #;
|
||||
%put # Assume that the `SPFinit.sas` file #;
|
||||
%put # is located in one of "C:/SAS_PK1" or "C:/SAS_PK2" folders. #;
|
||||
%put # #;
|
||||
%put # Run the following code in your SAS session: #;
|
||||
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas;
|
||||
%put %nrstr( filename packages ("C:/SAS_PK1" "C:/SAS_PK2"); %%* setup a directory for packages; );
|
||||
%put %nrstr( %%include packages(SPFinit.sas); %%* enable the framework; );
|
||||
%put ;
|
||||
%put %nrstr( filename packages ("D:/NEW_DIR" %%extendPackagesFileref()); %%* add new directory; );
|
||||
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;
|
||||
%put ###########################################################################################;
|
||||
%put ;
|
||||
options &options_tmp.;
|
||||
%GOTO ENDextendPackagesFileref;
|
||||
%end;
|
||||
|
||||
%if %superq(packages) = %then %let packages = packages;
|
||||
%if %qsysfunc(pathname(&packages.)) ne %then
|
||||
%do;
|
||||
%if %qsubstr(%qsysfunc(pathname(&packages.)), 1, 1) = %str(%() %then
|
||||
%do;
|
||||
%local length;
|
||||
%let length = %eval(%length(%qsysfunc(pathname(&packages.)))-2);
|
||||
%unquote(%qsubstr(%qsysfunc(pathname(&packages.)), 2, &length.))
|
||||
%end;
|
||||
%else "%sysfunc(pathname(&packages.))";
|
||||
%end;
|
||||
%ENDextendPackagesFileref:
|
||||
%mend extendPackagesFileref;
|
||||
|
||||
/* Examples:
|
||||
|
||||
filename packages "C:\";
|
||||
%include packages(SPFinit.sas)
|
||||
|
||||
%extendPackagesFileref(HELP)
|
||||
|
||||
filename packages (%extendPackagesFileref() "D:\");
|
||||
filename packages list;
|
||||
|
||||
filename packages clear;
|
||||
|
||||
filename packages "C:\";
|
||||
filename packages ("D:\" %extendPackagesFileref());
|
||||
filename packages list;
|
||||
|
||||
%put *%extendPackagesFileref()*;
|
||||
|
||||
|
||||
|
||||
*/
|
||||
|
||||
3809
SPF/Macros/generatepackage.sas
Normal file
3809
SPF/Macros/generatepackage.sas
Normal file
File diff suppressed because it is too large
Load Diff
183
SPF/Macros/helppackage.sas
Normal file
183
SPF/Macros/helppackage.sas
Normal file
@@ -0,0 +1,183 @@
|
||||
/*+helpPackage+*/
|
||||
/*** HELP START ***/
|
||||
|
||||
%macro helpPackage(
|
||||
packageName /* name of a package,
|
||||
e.g. myPackageFile.zip,
|
||||
required and not null */
|
||||
, helpKeyword /* phrase to search in help,
|
||||
when empty prints description
|
||||
"*" means print all help
|
||||
"license" prints license */
|
||||
, path = %sysfunc(pathname(packages)) /* location of a package,
|
||||
by default it looks for
|
||||
location of "packages" fileref */
|
||||
, options = %str(LOWCASE_MEMNAME) /* possible options for ZIP filename */
|
||||
, source2 = /*source2*/ /* option to print out details,
|
||||
null by default */
|
||||
, zip = zip /* standard package is zip (lowcase),
|
||||
e.g. %helpPackage(PiPackage,*)
|
||||
if the zip is not available use a folder
|
||||
unpack data to "pipackage.disk" folder
|
||||
and use helpPackage in the form:
|
||||
%helpPackage(PiPackage, *, zip=disk, options=) */
|
||||
, packageContentDS = 0 /* indicates if a data set with package
|
||||
content should be generated in WORK,
|
||||
if set to 1 then WORK.packageName_content
|
||||
dataset is created
|
||||
*/
|
||||
)/secure
|
||||
/*** HELP END ***/
|
||||
des = 'Macro to get help about SAS package, version 20231210. Run %helpPackage() for help info.'
|
||||
;
|
||||
%if (%superq(packageName) = ) OR (%qupcase(&packageName.) = HELP) %then
|
||||
%do;
|
||||
%local options_tmp ;
|
||||
%let options_tmp = ls=%sysfunc(getoption(ls))ps=%sysfunc(getoption(ps))
|
||||
%sysfunc(getoption(notes)) %sysfunc(getoption(source))
|
||||
msglevel=%sysfunc(getoption(msglevel))
|
||||
;
|
||||
options NOnotes NOsource ls=MAX ps=MAX msglevel=N;
|
||||
%put ;
|
||||
%put #################################################################################;
|
||||
%put ### This is short help information for the `helpPackage` macro #;
|
||||
%put #-------------------------------------------------------------------------------#;
|
||||
%put # #;
|
||||
%put # Macro to get help about SAS packages, version `20231210` #;
|
||||
%put # #;
|
||||
%put # A SAS package is a zip file containing a group #;
|
||||
%put # of SAS codes (macros, functions, data steps generating #;
|
||||
%put # data, etc.) wrapped up together and provided with #;
|
||||
%put # a single `help.sas` file (also embedded inside the zip). #;
|
||||
%put # #;
|
||||
%put # The `%nrstr(%%helpPackage())` macro prints in the SAS log help #;
|
||||
%put # information about the package provided by the developer. #;
|
||||
%put # #;
|
||||
%put #-------------------------------------------------------------------------------#;
|
||||
%put # #;
|
||||
%put #### Parameters: #;
|
||||
%put # #;
|
||||
%put # 1. `packageName` *Required.* Name of a package, e.g. myPackage, #;
|
||||
%put # Required and not null, default use case: #;
|
||||
%put # `%nrstr(%%helpPackage(myPackage)).` #;
|
||||
%put # If empty displays this help information. #;
|
||||
%put # #;
|
||||
%put # 2. `helpKeyword` *Optional.* A phrase to search in help, #;
|
||||
%put # - when empty prints description, #;
|
||||
%put # - "*" means: print all help, #;
|
||||
%put # - "license" prints the license. #;
|
||||
%put # #;
|
||||
%put # - `path=` *Optional.* Location of a package. By default it #;
|
||||
%put # looks for location of the **packages** fileref, i.e. #;
|
||||
%put # `%nrstr(%%sysfunc(pathname(packages)))` #;
|
||||
%put # #;
|
||||
%put # - `options=` *Optional.* Possible options for ZIP filename, #;
|
||||
%put # default value: `LOWCASE_MEMNAME` #;
|
||||
%put # #;
|
||||
%put # - `source2=` *Optional.* Option to print out details about #;
|
||||
%put # what is loaded, null by default. #;
|
||||
%put # #;
|
||||
%put # - `zip=` Standard package is zip (lowcase), #;
|
||||
%put # e.g. `%nrstr(%%helpPackage(PiPackage))`. #;
|
||||
%put # If the zip is not available use a folder. #;
|
||||
%put # Unpack data to "pipackage.disk" folder #;
|
||||
%put # and use helpPackage in the following form: #;
|
||||
%put # `%nrstr(%%helpPackage(PiPackage, ,zip=disk, options=))` #;
|
||||
%put # #;
|
||||
%put # - `packageContentDS=` *Optional.* Indicates if a data set with package #;
|
||||
%put # content should be generated in `WORK`, #;
|
||||
%put # with default value (`0`) the dataset is not produced, #;
|
||||
%put # if set to `1` then `WORK.packageName_content`. #;
|
||||
%put # #;
|
||||
%put #-------------------------------------------------------------------------------#;
|
||||
%put # #;
|
||||
%put # Visit: `https://github.com/yabwon/SAS_PACKAGES/tree/main/SPF/Documentation` #;
|
||||
%put # to learn more. #;
|
||||
%put # #;
|
||||
%put #### Example ####################################################################;
|
||||
%put # #;
|
||||
%put # Enabling the SAS Package Framework #;
|
||||
%put # from the local directory and installing & loading #;
|
||||
%put # the SQLinDS package from the Internet. #;
|
||||
%put # #;
|
||||
%put # Assume that the `SPFinit.sas` file #;
|
||||
%put # is located in the "C:/SAS_PACKAGES/" folder. #;
|
||||
%put # #;
|
||||
%put # Run the following code in your SAS session: #;
|
||||
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas;
|
||||
%put %nrstr( filename packages "C:/SAS_PACKAGES"; %%* setup a directory for packages; );
|
||||
%put %nrstr( %%include packages(SPFinit.sas); %%* enable the framework; );
|
||||
%put ;
|
||||
%put %nrstr( %%installPackage(SQLinDS) %%* install the package from the Internet; );
|
||||
%put %nrstr( %%helpPackage(SQLinDS) %%* get help about the package; );
|
||||
%put %nrstr( %%loadPackage(SQLinDS) %%* load the package content into the SAS session; );
|
||||
%put %nrstr( %%unloadPackage(SQLinDS) %%* unload the package content from the SAS session; );
|
||||
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;
|
||||
%put #################################################################################;
|
||||
%put ;
|
||||
options &options_tmp.;
|
||||
%GOTO ENDofhelpPackage;
|
||||
%end;
|
||||
|
||||
/* local variables for options */
|
||||
%local ls_tmp ps_tmp notes_tmp source_tmp msglevel_tmp;
|
||||
%let ls_tmp = %sysfunc(getoption(ls));
|
||||
%let ps_tmp = %sysfunc(getoption(ps));
|
||||
%let notes_tmp = %sysfunc(getoption(notes));
|
||||
%let source_tmp = %sysfunc(getoption(source));
|
||||
%let msglevel_tmp = %sysfunc(getoption(msglevel));
|
||||
|
||||
options NOnotes NOsource ls=MAX ps=MAX msglevel=N;
|
||||
|
||||
%local _PackageFileref_;
|
||||
/* %let _PackageFileref_ = P%sysfunc(MD5(%lowcase(&packageName.)),hex7.); */
|
||||
data _null_; call symputX("_PackageFileref_", "P" !! put(MD5("%lowcase(&packageName.)"), hex7. -L), "L"); run;
|
||||
|
||||
/* when the packages reference is multi-directory search for the first one containing the package */
|
||||
data _null_;
|
||||
exists = 0;
|
||||
length packages $ 32767 p $ 4096;
|
||||
packages = resolve(symget("path"));
|
||||
if char(packages,1) ^= "(" then packages = quote(strip(packages)); /* for paths with spaces */
|
||||
do i = 1 to kcountw(packages, "()", "QS");
|
||||
p = dequote(kscanx(packages, i, "()", "QS"));
|
||||
exists + fileexist(catx("/", p, "%lowcase(&packageName.).&zip."));
|
||||
if exists then leave;
|
||||
end;
|
||||
if exists then call symputx("path", p, "L");
|
||||
run;
|
||||
|
||||
filename &_PackageFileref_. &ZIP.
|
||||
/* put location of package myPackageFile.zip here */
|
||||
"&path./%lowcase(&packageName.).&zip." %unquote(&options.)
|
||||
;
|
||||
%if %sysfunc(fexist(&_PackageFileref_.)) %then
|
||||
%do;
|
||||
%include &_PackageFileref_.(packagemetadata.sas) / &source2.;
|
||||
filename &_PackageFileref_. clear;
|
||||
options ls = &ls_tmp. ps = &ps_tmp. ¬es_tmp. &source_tmp.;
|
||||
filename &_PackageFileref_. &ZIP.
|
||||
"&path./%lowcase(&packageName.).&zip." %unquote(&options.)
|
||||
ENCODING =
|
||||
%if %bquote(&packageEncoding.) NE %then &packageEncoding. ;
|
||||
%else utf8 ;
|
||||
;
|
||||
%if 1=%superq(packageContentDS) %then %let packageContentDS=work.&packageName._content;
|
||||
%else %let packageContentDS=;
|
||||
|
||||
%include &_PackageFileref_.(help.sas) / &source2.;
|
||||
%end;
|
||||
%else %put ERROR:[&sysmacroname] File "&path./&packageName..&zip." does not exist!;
|
||||
filename &_PackageFileref_. clear;
|
||||
|
||||
options ls = &ls_tmp. ps = &ps_tmp. ¬es_tmp. &source_tmp. msglevel = &msglevel_tmp.;
|
||||
|
||||
%ENDofhelpPackage:
|
||||
%mend helpPackage;
|
||||
|
||||
/*
|
||||
TODO:
|
||||
- macro for testing available packages in the packages folder [DONE] checkout: %listPackages()
|
||||
- add MD5(&packageName.) value hash instead "package" word in filenames [DONE]
|
||||
*/
|
||||
|
||||
488
SPF/Macros/installpackage.sas
Normal file
488
SPF/Macros/installpackage.sas
Normal file
@@ -0,0 +1,488 @@
|
||||
/*+installPackage+*/
|
||||
/* Macros to install SAS packages, version 20231210 */
|
||||
/* A SAS package is a zip file containing a group of files
|
||||
with SAS code (macros, functions, data steps generating
|
||||
data, etc.) wrapped up together and %INCLUDEed by
|
||||
a single load.sas file (also embedded inside the zip).
|
||||
*/
|
||||
/*** HELP START ***/
|
||||
|
||||
%macro installPackage(
|
||||
packagesNames /* space separated list of packages names, without the zip extension */
|
||||
, sourcePath = /* location of the package, e.g. "www.some.page/", mind the "/" at the end */
|
||||
, mirror = 0 /* indicates which location for package source should be used */
|
||||
, version = /* indicates which version of a package to install */
|
||||
, replace = 1 /* 1 = replace if the package already exist, 0 = otherwise */
|
||||
, URLuser = /* user name for the password protected URLs */
|
||||
, URLpass = /* password for the password protected URLs */
|
||||
, URLoptions = /* options for the `sourcePath` URLs */
|
||||
, loadAddCnt=0 /* should the additional content be loaded?
|
||||
default is 0 - means No, 1 means Yes */
|
||||
)
|
||||
/secure
|
||||
minoperator
|
||||
/*** HELP END ***/
|
||||
des = 'Macro to install SAS package, version 20231210. Run %%installPackage() for help info.'
|
||||
;
|
||||
%if (%superq(packagesNames) = ) OR (%qupcase(&packagesNames.) = HELP) %then
|
||||
%do;
|
||||
%local options_tmp ;
|
||||
%let options_tmp = ls=%sysfunc(getoption(ls))ps=%sysfunc(getoption(ps))
|
||||
%sysfunc(getoption(notes)) %sysfunc(getoption(source))
|
||||
msglevel=%sysfunc(getoption(msglevel))
|
||||
;
|
||||
options NOnotes NOsource ls=MAX ps=MAX msglevel=N;
|
||||
%put ;
|
||||
%put ##############################################################################################;
|
||||
%put ### This is short help information for the `installPackage` macro #;
|
||||
%put #--------------------------------------------------------------------------------------------#;;
|
||||
%put # #;
|
||||
%put # Macro to install SAS packages, version `20231210` #;
|
||||
%put # #;
|
||||
%put # A SAS package is a zip file containing a group #;
|
||||
%put # of SAS codes (macros, functions, data steps generating #;
|
||||
%put # data, etc.) wrapped up together and embedded inside the zip. #;
|
||||
%put # #;
|
||||
%put # The `%nrstr(%%installPackage())` macro installs the package zip #;
|
||||
%put # in the packages folder. The process of installation is equivalent with #;
|
||||
%put # manual downloading the package zip file into the packages folder. #;
|
||||
%put # #;
|
||||
%put # In case the packages fileref is a multi-directory one the first directory #;
|
||||
%put # will be selected as a destination. #;
|
||||
%put # #;
|
||||
%put #--------------------------------------------------------------------------------------------#;
|
||||
%put # #;
|
||||
%put #### Parameters: #;
|
||||
%put # #;
|
||||
%put # 1. `packagesNames` Space separated list of packages names _without_ #;
|
||||
%put # the zip extension, e.g. myPackage1 myPackage2, #;
|
||||
%put # Required and not null, default use case: #;
|
||||
%put # `%nrstr(%%installPackage(myPackage1 myPackage2))`. #;
|
||||
%put # If empty displays this help information. #;
|
||||
%put # If the package name is *SPFinit* or *SASPackagesFramework* #;
|
||||
%put # then the framework itself is downloaded. #;
|
||||
%put # #;
|
||||
%put # - `sourcePath=` Location of the package, e.g. "www.some.web.page/" #;
|
||||
%put # Mind the "/" at the end of the path! #;
|
||||
%put # Current default location for packages is: #;
|
||||
%put # `https://github.com/SASPAC/` #;
|
||||
%put # Current default location for the framework is: #;
|
||||
%put # `https://raw.githubusercontent.com/yabwon/SAS_PACKAGES/main/SPF/` #;
|
||||
%put # #;
|
||||
%put # - `mirror=` Indicates which web location for packages installation is used. #;
|
||||
%put # Value `0` indicates: #;
|
||||
%put # `https://github.com/SASPAC/` #;
|
||||
%put # Value `1` indicates: #;
|
||||
%put # `https://raw.githubusercontent.com/yabwon/SAS_PACKAGES/main` #;
|
||||
%put # Value `2` indicates: #;
|
||||
%put # `https://pages.mini.pw.edu.pl/~jablonskib/SASpublic/SAS_PACKAGES` #;
|
||||
%put # Default value is `0`. #;
|
||||
%put # #;
|
||||
%put # - `version=` Indicates which historical version of a package to install. #;
|
||||
%put # Historical version are available only if `mirror=0` is set. #;
|
||||
%put # Default value is null which means "install the latest". #;
|
||||
%put # When there are multiple packages to install version #;
|
||||
%put # is scan sequentially. #;
|
||||
%put # #;
|
||||
%put # - `replace=` With default value of `1` it causes existing package file #;
|
||||
%put # to be replaced by new downloaded file. #;
|
||||
%put # #;
|
||||
%put # - `URLuser=` A user name for the password protected URLs, no quotes needed. #;
|
||||
%put # #;
|
||||
%put # - `URLpass=` A password for the password protected URLs, no quotes needed. #;
|
||||
%put # #;
|
||||
%put # - `URLoptions=` Options for the `sourcePath` URLs filename. Consult the SAS #;
|
||||
%put # documentation for the further details. #;
|
||||
%put # #;
|
||||
%put # - `loadAddCnt=` *Optional.* A package zip may contain additional #;
|
||||
%put # content. The option indicates if it should be loaded #;
|
||||
%put # Default value of zero (`0`) means "No", one (`1`) #;
|
||||
%put # means "Yes". Content is extracted into the **packages** fileref #;
|
||||
%put # directory in `<packageName>_AdditionalContent` folder. #;
|
||||
%put # For other locations use `%nrstr(%%loadPackageAddCnt())` macro. #;
|
||||
%put # #;
|
||||
%put #--------------------------------------------------------------------------------------------#;
|
||||
%put # #;
|
||||
%put # Visit: `https://github.com/yabwon/SAS_PACKAGES/tree/main/SPF/Documentation` #;
|
||||
%put # to learn more. #;
|
||||
%put # #;
|
||||
%put #### Example #################################################################################;
|
||||
%put # #;
|
||||
%put # Enabling the SAS Package Framework #;
|
||||
%put # from the local directory and installing & loading #;
|
||||
%put # the SQLinDS package from the Internet. #;
|
||||
%put # #;
|
||||
%put # Assume that the `SPFinit.sas` file #;
|
||||
%put # is located in the "C:/SAS_PACKAGES/" folder. #;
|
||||
%put # #;
|
||||
%put # Run the following code in your SAS session: #;
|
||||
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas;
|
||||
%put %nrstr( filename packages "C:/SAS_PACKAGES"; %%* setup a directory for packages; );
|
||||
%put %nrstr( %%include packages(SPFinit.sas); %%* enable the framework; );
|
||||
%put ;
|
||||
%put %nrstr( %%installPackage(SQLinDS) %%* install the package from the Internet; );
|
||||
%put %nrstr( %%helpPackage(SQLinDS) %%* get help about the package; );
|
||||
%put %nrstr( %%loadPackage(SQLinDS) %%* load the package content into the SAS session; );
|
||||
%put %nrstr( %%unloadPackage(SQLinDS) %%* unload the package content from the SAS session; );
|
||||
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;
|
||||
%put #### Example #################################################################################;
|
||||
%put # #;
|
||||
%put # Enabling the SAS Package Framework #;
|
||||
%put # from the local directory and installing & loading #;
|
||||
%put # the multiple packages from the Internet. #;
|
||||
%put # #;
|
||||
%put # Assume that the `SPFinit.sas` file #;
|
||||
%put # is located in the "C:/SAS_PACKAGES/" folder. #;
|
||||
%put # #;
|
||||
%put # Run the following code in your SAS session: #;
|
||||
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas;
|
||||
%put %nrstr( filename packages "C:/SAS_PACKAGES"; );
|
||||
%put %nrstr( %%include packages(SPFinit.sas); );
|
||||
%put ;
|
||||
%put %nrstr( %%installPackage(baseplus(1.17) macroarray(1.0) dfa(0.5) GSM) );
|
||||
%put %nrstr( %%loadPackageS(GSM, baseplus(1.17), macroarray(1.0), dfa(0.5)) );
|
||||
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;
|
||||
%put ##############################################################################################;
|
||||
%put ;
|
||||
options &options_tmp.;
|
||||
%GOTO ENDofinstallPackage;
|
||||
%end;
|
||||
|
||||
/* local variables for options */
|
||||
%local ls_tmp ps_tmp notes_tmp source_tmp stimer_tmp fullstimer_tmp msglevel_tmp;
|
||||
|
||||
%let ls_tmp = %sysfunc(getoption(ls));
|
||||
%let ps_tmp = %sysfunc(getoption(ps));
|
||||
%let notes_tmp = %sysfunc(getoption(notes));
|
||||
%let source_tmp = %sysfunc(getoption(source));
|
||||
%let stimer_tmp = %sysfunc(getoption(stimer));
|
||||
%let fullstimer_tmp = %sysfunc(getoption(fullstimer));
|
||||
%let msglevel_tmp = %sysfunc(getoption(msglevel));
|
||||
|
||||
options NOnotes NOsource ls=MAX ps=MAX NOfullstimer NOstimer msglevel=N;
|
||||
|
||||
/*
|
||||
Reference:
|
||||
https://blogs.sas.com/content/sasdummy/2011/06/17/how-to-use-sas-data-step-to-copy-a-file-from-anywhere/
|
||||
*/
|
||||
|
||||
/* in case the 'packages' fileref is multi-directory the first directory will be selected as a destination */
|
||||
data _null_;
|
||||
if "(" =: pathname("packages") then
|
||||
/* get the firstPackagesPath */
|
||||
call symputX("firstPackagesPath", dequote(kscanx(pathname("packages"), 1, "()", "QS")), "L");
|
||||
else
|
||||
call symputX("firstPackagesPath", pathname("packages"), "L");
|
||||
run;
|
||||
|
||||
%if %superq(sourcePath)= %then
|
||||
%do;
|
||||
%local SPFinitMirror;
|
||||
/* the defaults are: */
|
||||
%let SPFinitMirror = https://raw.githubusercontent.com/yabwon/SAS_PACKAGES/main/SPF/SPFinit.sas;
|
||||
%let sourcePath = https://raw.githubusercontent.com/yabwon/SAS_PACKAGES/main/packages/;
|
||||
|
||||
%if 0 = %superq(mirror) %then
|
||||
%do;
|
||||
%let SPFinitMirror = https://raw.githubusercontent.com/yabwon/SAS_PACKAGES/main/SPF/SPFinit.sas;
|
||||
%let sourcePath = https://github.com/SASPAC/; /*usercontent*/
|
||||
%goto mirrorEnd;
|
||||
%end;
|
||||
|
||||
%if 1 = %superq(mirror) %then
|
||||
%do;
|
||||
%let SPFinitMirror = https://raw.githubusercontent.com/yabwon/SAS_PACKAGES/main/SPF/SPFinit.sas;
|
||||
%let sourcePath = https://raw.githubusercontent.com/yabwon/SAS_PACKAGES/main/packages/;
|
||||
%goto mirrorEnd;
|
||||
%end;
|
||||
|
||||
%if 2 = %superq(mirror) %then
|
||||
%do;
|
||||
%let SPFinitMirror = https://pages.mini.pw.edu.pl/~jablonskib/SASpublic/SAS_PACKAGES/SPF/SPFinit.sas;
|
||||
%let sourcePath = https://pages.mini.pw.edu.pl/~jablonskib/SASpublic/SAS_PACKAGES/packages/;
|
||||
%goto mirrorEnd;
|
||||
%end;
|
||||
%mirrorEnd:
|
||||
%put INFO: Source path is &sourcePath.;
|
||||
%end;
|
||||
%else
|
||||
%do;
|
||||
%let mirror=-1;
|
||||
%let SPFinitMirror = &sourcePath.SPFinit.sas;
|
||||
%end;
|
||||
|
||||
%local i str;
|
||||
/* standardise list of packages */
|
||||
%let str = %qsysfunc(compress(%superq(packagesNames),[{(. _)}],kad));
|
||||
%let str = %qsysfunc(translate(%superq(str),[[]],{()}));
|
||||
%let str = %qsysfunc(transtrn(%superq(str),],%str(] )));
|
||||
%let str = %qsysfunc(compbl(%superq(str)));
|
||||
%let str = %qsysfunc(transtrn(%superq(str),%str([ ),[));
|
||||
%let str = %qsysfunc(transtrn(%superq(str),%str( [),[));
|
||||
%let str = %qsysfunc(transtrn(%superq(str),%str( ]),]));
|
||||
%let str = %unquote(&str.);
|
||||
%let packagesNames = %qsysfunc(translate(%superq(str),(),[]));
|
||||
|
||||
%if %length("%sysfunc(compress(%superq(str),[,k))") NE %length("%sysfunc(compress(%superq(str),],k))") %then
|
||||
%do;
|
||||
%put ERROR: Syntax error in list of packages!;
|
||||
%put ERROR- %superq(packagesNames);
|
||||
%goto packagesListError;
|
||||
%end;
|
||||
|
||||
%put ;
|
||||
%put INFO: Calling: &packagesNames.;
|
||||
|
||||
%do i = 1 %to %sysfunc(countw(&packagesNames., , S));
|
||||
/*-++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-*/
|
||||
%local packageName packageSubDir vers versA versB;
|
||||
%put ;
|
||||
/*%put ### %scan(&packagesNames., &i., , S) ###;*/
|
||||
%let packageName = %scan(%scan(&packagesNames., &i., , S),1,{[()]});
|
||||
%let versA = %scan(%scan(&packagesNames., &i., , S),2,{[()]});
|
||||
%let versB = %scan(&version., &i., , S);
|
||||
%let vers=;
|
||||
%if %superq(versB) ne %then %let vers = &versB.;
|
||||
%if %superq(versA) ne %then %let vers = &versA.;
|
||||
%if -1 = &mirror %then /* ignore version when direct path is provided */
|
||||
%do;
|
||||
%let vers=;
|
||||
%end;
|
||||
%put ### &packageName.(&vers.) ###;
|
||||
|
||||
%put *** %lowcase(&packageName.) start *****************************************;
|
||||
%local in out _IOFileref_;
|
||||
data _null_; call symputX("_IOFileref_", put(MD5("%lowcase(&packageName.)"), hex7. -L), "L"); run;
|
||||
%let in = i&_IOFileref_.;
|
||||
%let out = o&_IOFileref_.;
|
||||
/* %let in = i%sysfunc(md5(&packageName.),hex7.); */
|
||||
/* %let out = o%sysfunc(md5(&packageName.),hex7.); */
|
||||
|
||||
/*options MSGLEVEL=i;*/
|
||||
%if %upcase(&packageName.) in (SPFINIT SASPACKAGEFRAMEWORK SASPACKAGESFRAMEWORK) %then
|
||||
%do;
|
||||
/* allows to install/download the framework file like any other package */
|
||||
%if %superq(mirror) in (0 1) AND (%superq(vers) ne) %then
|
||||
%do;
|
||||
%let SPFinitMirror = https://raw.githubusercontent.com/yabwon/SAS_PACKAGES/&vers./SPF/SPFinit.sas;
|
||||
%end;
|
||||
|
||||
filename &in URL
|
||||
"&SPFinitMirror."
|
||||
recfm=N lrecl=1;
|
||||
filename &out
|
||||
"&firstPackagesPath./SPFinit.sas"
|
||||
recfm=N lrecl=1;
|
||||
%end;
|
||||
%else
|
||||
%do;
|
||||
%if 0 = %superq(mirror) %then
|
||||
%do;
|
||||
%let packageSubDir = %lowcase(&packageName.)/raw/main/;
|
||||
|
||||
%if %superq(vers) ne %then
|
||||
%do;
|
||||
/*%let packageSubDir = %lowcase(&packageName.)/main/hist/&version./;*/
|
||||
%let packageSubDir = %lowcase(&packageName.)/raw/&vers./;
|
||||
%end;
|
||||
%end;
|
||||
filename &in URL "&sourcePath.&packageSubDir.%lowcase(&packageName.).zip"
|
||||
%if (%superq(URLuser) ne ) %then
|
||||
%do;
|
||||
user = "&URLuser."
|
||||
pass = "&URLuser."
|
||||
%end;
|
||||
&URLoptions.
|
||||
recfm=N lrecl=1;
|
||||
filename &out "&firstPackagesPath./%lowcase(&packageName.).zip" recfm=N lrecl=1;
|
||||
%end;
|
||||
/*
|
||||
filename in list;
|
||||
filename out list;
|
||||
*/
|
||||
/* copy the file byte-by-byte */
|
||||
%local installationRC;
|
||||
%let installationRC=1;
|
||||
data _null_;
|
||||
length filein 8 out_path in_path $ 4096;
|
||||
out_path = pathname ("&out");
|
||||
in_path = pathname ("&in" );
|
||||
|
||||
|
||||
filein = fopen( "&in", 'S', 1, 'B');
|
||||
if filein = 0 then
|
||||
put "ERROR: Source file:" /
|
||||
"ERROR- " in_path /
|
||||
"ERROR- is unavailable!";
|
||||
if filein > 0;
|
||||
|
||||
put @2 "Source information:";
|
||||
infonum = FOPTNUM(filein);
|
||||
length infoname $ 32 infoval $ 128;
|
||||
do i=1 to coalesce(infonum, -1);
|
||||
infoname = FOPTNAME(filein, i);
|
||||
infoval = FINFO(filein, infoname);
|
||||
put @4 infoname ":"
|
||||
/ @6 infoval
|
||||
;
|
||||
end;
|
||||
rc = FCLOSE(filein);
|
||||
put;
|
||||
|
||||
if FEXIST("&out") = 0 then
|
||||
do;
|
||||
put @2 "Installing the &packageName. package"
|
||||
/ @2 "in the &firstPackagesPath. directory.";
|
||||
rc = FCOPY("&in", "&out");
|
||||
end;
|
||||
else if FEXIST("&out") = 1 then
|
||||
do;
|
||||
if symgetn("replace")=1 then
|
||||
do;
|
||||
put @2 "The following file will be replaced during "
|
||||
/ @2 "installation of the &packageName. package: "
|
||||
/ @5 out_path;
|
||||
rc = FDELETE("&out");
|
||||
rc = FCOPY("&in", "&out");
|
||||
end;
|
||||
else
|
||||
do;
|
||||
put @2 "The following file will NOT be replaced: "
|
||||
/ @5 out_path;
|
||||
rc = 1;
|
||||
end;
|
||||
end;
|
||||
|
||||
put @2 "Done with return code " rc= "(zero = success)";
|
||||
call symputX("installationRC", rc, "L");
|
||||
run;
|
||||
|
||||
filename &in clear;
|
||||
filename &out clear;
|
||||
|
||||
%if 1 = &loadAddCnt.
|
||||
AND 0 = &installationRC.
|
||||
AND NOT (%upcase(&packageName.) in (SPFINIT SASPACKAGEFRAMEWORK SASPACKAGESFRAMEWORK))
|
||||
%then
|
||||
%do;
|
||||
%put; %put - Additional content loading - Start -;
|
||||
%loadPackageAddCnt(&packageName.
|
||||
,path=&firstPackagesPath.
|
||||
,target=&firstPackagesPath.
|
||||
)
|
||||
%put - Additional content loading - End -;
|
||||
%end;
|
||||
%put *** %lowcase(&packageName.) end *******************************************;
|
||||
/*-++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-*/
|
||||
%end;
|
||||
|
||||
%packagesListError:
|
||||
|
||||
options ls = &ls_tmp. ps = &ps_tmp.
|
||||
¬es_tmp. &source_tmp.
|
||||
&stimer_tmp. &fullstimer_tmp.
|
||||
msglevel=&msglevel_tmp.;
|
||||
|
||||
%ENDofinstallPackage:
|
||||
%mend installPackage;
|
||||
|
||||
/*** HELP START ***/
|
||||
|
||||
/*
|
||||
Filenames references "packages" and "package" are reserved keywords.
|
||||
The first one should be used to point local folder with packages.
|
||||
The second is used internally by macros.
|
||||
Do not use them otherwise than:
|
||||
filename packages "</the/folder/with/sas/packages>";
|
||||
since it may affect stability of the framework.
|
||||
**/
|
||||
|
||||
/* Example 1: Enabling the SAS Package Framework
|
||||
and loading the SQLinDS package from the local directory.
|
||||
|
||||
Assume that the SPFinit.sas file and the SQLinDS
|
||||
package (sqlinds.zip file) are located in
|
||||
the "C:/SAS_PACKAGES/" folder.
|
||||
|
||||
Run the following code in your SAS session:
|
||||
|
||||
filename packages "C:/SAS_PACKAGES"; %* setup a directory for packages;
|
||||
%include packages(SPFinit.sas); %* enable the framework;
|
||||
|
||||
%helpPackage(SQLinDS) %* get help about the package;
|
||||
%loadPackage(SQLinDS) %* load the package content into the SAS session;
|
||||
%unloadPackage(SQLinDS) %* unload the package content from the SAS session;
|
||||
*/
|
||||
|
||||
/* Example 2: Enabling the SAS Package Framework
|
||||
from the local directory and installing & loading
|
||||
the SQLinDS package from the Internet.
|
||||
|
||||
Assume that the SPFinit.sas file
|
||||
is located in the "C:/SAS_PACKAGES/" folder.
|
||||
|
||||
Run the following code in your SAS session:
|
||||
|
||||
filename packages "C:/SAS_PACKAGES"; %* setup a directory for packages;
|
||||
%include packages(SPFinit.sas); %* enable the framework;
|
||||
|
||||
%installPackage(SQLinDS) %* install the package from the Internet;
|
||||
%helpPackage(SQLinDS) %* get help about the package;
|
||||
%loadPackage(SQLinDS) %* load the package content into the SAS session;
|
||||
%unloadPackage(SQLinDS) %* unload the package content from the SAS session;
|
||||
*/
|
||||
|
||||
/* Example 3: Enabling the SAS Package Framework
|
||||
and installing & loading the SQLinDS package
|
||||
from the Internet.
|
||||
|
||||
Run the following code in your SAS session:
|
||||
|
||||
filename packages "%sysfunc(pathname(work))"; %* setup WORK as a temporary directory for packages;
|
||||
|
||||
filename spfinit url "https://raw.githubusercontent.com/yabwon/SAS_PACKAGES/main/SPFinit.sas";
|
||||
%include spfinit; %* enable the framework;
|
||||
|
||||
%installPackage(SQLinDS) %* install the package from the Internet;
|
||||
%helpPackage(SQLinDS) %* get help about the package;
|
||||
%loadPackage(SQLinDS) %* load the package content into the SAS session;
|
||||
%unloadPackage(SQLinDS) %* unload the package content from the SAS session;
|
||||
*/
|
||||
|
||||
/* Example 4:
|
||||
Assume that the SPFinit.sas file and the SQLinDS package (sqlinds.zip file)
|
||||
are located in the "C:/SAS_PACKAGES/" folder.
|
||||
|
||||
In case when user SAS session does not support ZIP fileref
|
||||
the following solution could be used.
|
||||
|
||||
Unzip the packagename.zip content into the packagename.disk folder
|
||||
and run macros with the following options: ;
|
||||
|
||||
%loadPackage(packageName,zip=disk,options=)
|
||||
%helpPackage(packageName,,zip=disk,options=) %* mind the double comma!! ;
|
||||
%unloadPackage(packageName,zip=disk,options=)
|
||||
|
||||
*/
|
||||
|
||||
/* Example 5: Enabling the SAS Package Framework from the local directory
|
||||
and installing the SQLinDS package from the Internet.
|
||||
|
||||
Assume that the SPFinit.sas file is located in
|
||||
the "C:/SAS_PACKAGES/" folder.
|
||||
|
||||
filename packages "C:/SAS_PACKAGES"; %* setup a directory for packages;
|
||||
%include packages(SPFinit.sas); %* enable the framework;
|
||||
|
||||
%installPackage(SQLinDS); %* install package;
|
||||
%installPackage(SQLinDS); %* overwrite already installed package;
|
||||
%installPackage(SQLinDS,replace=0); %* prevent overwrite installed package;
|
||||
|
||||
|
||||
%installPackage(NotExistingPackage); %* handling with not existing package;
|
||||
|
||||
*/
|
||||
|
||||
/*** HELP END ***/
|
||||
|
||||
|
||||
185
SPF/Macros/listpackages.sas
Normal file
185
SPF/Macros/listpackages.sas
Normal file
@@ -0,0 +1,185 @@
|
||||
/*+listPackages+*/
|
||||
/*** HELP START ***//*
|
||||
|
||||
Macro to list SAS packages in packages folder.
|
||||
|
||||
Version 20231210
|
||||
|
||||
A SAS package is a zip file containing a group
|
||||
of SAS codes (macros, functions, data steps generating
|
||||
data, etc.) wrapped up together and %INCLUDEed by
|
||||
a single load.sas file (also embedded inside the zip).
|
||||
|
||||
|
||||
* Example 1: Set local packages directory, enable the framework,
|
||||
and list packages in the local repository.
|
||||
|
||||
filename packages "C:\SAS_PACKAGES";
|
||||
%include packages(SPFinit.sas);
|
||||
%listPackages()
|
||||
|
||||
*//*** HELP END ***/
|
||||
|
||||
|
||||
%macro listPackages()/secure PARMBUFF
|
||||
des = 'Macro to list SAS packages from `packages` fileref, type %listPackages(HELP) for help, version 20231210.'
|
||||
;
|
||||
%if %QUPCASE(&SYSPBUFF.) = %str(%(HELP%)) %then
|
||||
%do;
|
||||
%local options_tmp ;
|
||||
%let options_tmp = ls=%sysfunc(getoption(ls))ps=%sysfunc(getoption(ps))
|
||||
%sysfunc(getoption(notes)) %sysfunc(getoption(source))
|
||||
msglevel=%sysfunc(getoption(msglevel))
|
||||
;
|
||||
options NOnotes NOsource ls=MAX ps=MAX msglevel=N;
|
||||
%put ;
|
||||
%put ###########################################################################################;
|
||||
%put ### This is short help information for the `listPackages` macro #;
|
||||
%put #-----------------------------------------------------------------------------------------#;;
|
||||
%put # #;
|
||||
%put # Macro to list available SAS packages, version `20231210` #;
|
||||
%put # #;
|
||||
%put # A SAS package is a zip file containing a group #;
|
||||
%put # of SAS codes (macros, functions, data steps generating #;
|
||||
%put # data, etc.) wrapped up together and embedded inside the zip. #;
|
||||
%put # #;
|
||||
%put # The `%nrstr(%%listPackages())` macro lists packages available #;
|
||||
%put # in the packages folder. List is printed in the SAS Log. #;
|
||||
%put # #;
|
||||
%put #### Parameters: #;
|
||||
%put # #;
|
||||
%put # NO PARAMETERS #;
|
||||
%put # #;
|
||||
%put # When used as: `%nrstr(%%listPackages(HELP))` it displays this help information. #;
|
||||
%put # #;
|
||||
%put #-----------------------------------------------------------------------------------------#;
|
||||
%put # #;
|
||||
%put # Visit: `https://github.com/yabwon/SAS_PACKAGES/tree/main/SPF/Documentation` #;
|
||||
%put # to learn more. #;
|
||||
%put # #;
|
||||
%put #### Example ##############################################################################;
|
||||
%put # #;
|
||||
%put # Enabling the SAS Package Framework #;
|
||||
%put # from the local directory and listing #;
|
||||
%put # available packages. #;
|
||||
%put # #;
|
||||
%put # Assume that the `SPFinit.sas` file #;
|
||||
%put # is located in the "C:/SAS_PACKAGES/" folder. #;
|
||||
%put # #;
|
||||
%put # Run the following code in your SAS session: #;
|
||||
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas;
|
||||
%put %nrstr( filename packages "C:/SAS_PACKAGES"; %%* setup a directory for packages; );
|
||||
%put %nrstr( %%include packages(SPFinit.sas); %%* enable the framework; );
|
||||
%put ;
|
||||
%put %nrstr( %%listPackages() %%* list available packages; );
|
||||
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;
|
||||
%put ###########################################################################################;
|
||||
%put ;
|
||||
options &options_tmp.;
|
||||
%GOTO ENDoflistPackages;
|
||||
%end;
|
||||
|
||||
%local ls_tmp ps_tmp notes_tmp source_tmp filesWithCodes;
|
||||
|
||||
%let filesWithCodes = WORK._%sysfunc(datetime(), hex16.)_;
|
||||
|
||||
%let ls_tmp = %sysfunc(getoption(ls));
|
||||
%let ps_tmp = %sysfunc(getoption(ps));
|
||||
%let notes_tmp = %sysfunc(getoption(notes));
|
||||
%let source_tmp = %sysfunc(getoption(source));
|
||||
|
||||
options NOnotes NOsource ls=MAX ps=MAX;
|
||||
|
||||
data _null_;
|
||||
length baseAll $ 32767;
|
||||
baseAll = pathname("packages");
|
||||
|
||||
if baseAll = " " then
|
||||
do;
|
||||
put "NOTE: The file reference PACKAGES is not assigned.";
|
||||
stop;
|
||||
end;
|
||||
|
||||
if char(baseAll,1) ^= "(" then baseAll = quote(strip(baseAll)); /* for paths with spaces */
|
||||
|
||||
do k = 1 to kcountw(baseAll, "()", "QS"); drop k;
|
||||
base = dequote(kscanx(baseAll, k, "()", "QS"));
|
||||
|
||||
length folder $ 64 file $ 1024 folderRef fileRef $ 8;
|
||||
|
||||
folderRef = "_%sysfunc(datetime(), hex6.)0";
|
||||
|
||||
rc=filename(folderRef, base);
|
||||
folderid=dopen(folderRef);
|
||||
|
||||
putlog " ";
|
||||
put "/*" 100*"+" ;
|
||||
do i=1 to dnum(folderId); drop i;
|
||||
|
||||
if i = 1 then
|
||||
do;
|
||||
put " #";
|
||||
put " # Listing packages for: " base;
|
||||
put " #";
|
||||
end;
|
||||
|
||||
folder = dread(folderId, i);
|
||||
|
||||
fileRef = "_%sysfunc(datetime(), hex6.)1";
|
||||
rc = filename(fileRef, catx("/", base, folder));
|
||||
fileId = dopen(fileRef);
|
||||
|
||||
EOF = 0;
|
||||
if fileId = 0 and lowcase(kscanx(folder, -1, ".")) = 'zip' then
|
||||
do;
|
||||
file = catx('/',base, folder);
|
||||
|
||||
rc1 = filename("package", strip(file), 'zip', 'member="description.sas"');
|
||||
rcE = fexist("package");
|
||||
rc2 = filename("package", " ");
|
||||
|
||||
if rcE then /* if the description.sas exists in the zip then read it */
|
||||
do;
|
||||
putlog " * ";
|
||||
length nn $ 96;
|
||||
if (96-lengthn(file)) < 1 then
|
||||
put " * " file;
|
||||
else
|
||||
do;
|
||||
nn = repeat("*", (96-lengthn(file)));
|
||||
put " * " file nn;
|
||||
end;
|
||||
|
||||
infile _DUMMY_ ZIP FILEVAR=file member="description.sas" end=EOF;
|
||||
|
||||
do until(EOF);
|
||||
input;
|
||||
if strip(upcase(kscanx(_INFILE_,1,":"))) in ("PACKAGE" "TITLE" "VERSION" "AUTHOR" "MAINTAINER" "LICENSE") then
|
||||
do;
|
||||
_INFILE_ = kscanx(_INFILE_,1,":") !! ":" !! kscanx(_INFILE_,2,":");
|
||||
putlog " * " _INFILE_;
|
||||
end;
|
||||
if strip(upcase(strip(_INFILE_))) =: "DESCRIPTION START:" then leave;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
rc = dclose(fileId);
|
||||
rc = filename(fileRef);
|
||||
end;
|
||||
|
||||
putlog " * ";
|
||||
put 100*"+" "*/";
|
||||
rc = dclose(folderid);
|
||||
rc = filename(folderRef);
|
||||
end;
|
||||
|
||||
stop;
|
||||
run;
|
||||
|
||||
options ls = &ls_tmp. ps = &ps_tmp. ¬es_tmp. &source_tmp.;
|
||||
|
||||
%ENDoflistPackages:
|
||||
%mend listPackages;
|
||||
|
||||
|
||||
285
SPF/Macros/loadpackage.sas
Normal file
285
SPF/Macros/loadpackage.sas
Normal file
@@ -0,0 +1,285 @@
|
||||
/*+loadPackage+*/
|
||||
/*** HELP START ***/
|
||||
|
||||
%macro loadPackage(
|
||||
packageName /* name of a package,
|
||||
e.g. myPackage,
|
||||
required and not null */
|
||||
, path = %sysfunc(pathname(packages)) /* location of a package,
|
||||
by default it looks for
|
||||
location of "packages" fileref */
|
||||
, options = %str(LOWCASE_MEMNAME) /* possible options for ZIP filename */
|
||||
, source2 = /*source2*/ /* option to print out details,
|
||||
null by default */
|
||||
, requiredVersion = . /* option to test if loaded package
|
||||
is provided in required version */
|
||||
, lazyData = /* a list of names of lazy datasets
|
||||
to be loaded, if not null then
|
||||
datasets from the list are loaded
|
||||
instead of a package, asterisk
|
||||
means "load all datasets" */
|
||||
, zip = zip /* standard package is zip (lowcase),
|
||||
e.g. %loadPackage(PiPackage)
|
||||
if the zip is not available use a folder
|
||||
unpack data to "pipackage.disk" folder
|
||||
and use loadPackage in the form:
|
||||
%loadPackage(PiPackage, zip=disk, options=) */
|
||||
, cherryPick=* /* space separated list of selected elements of the package
|
||||
to be loaded into the session, default value "*" means
|
||||
"load all elements of the package" */
|
||||
, loadAddCnt=0 /* should the additional content be loaded?
|
||||
default is 0 - means No, 1 means Yes */
|
||||
, suppressExec=0 /* indicates if loading of exec files
|
||||
should be suppressed, 1=suppress
|
||||
*/
|
||||
)/secure
|
||||
/*** HELP END ***/
|
||||
des = 'Macro to load SAS package, version 20231210. Run %loadPackage() for help info.'
|
||||
minoperator
|
||||
;
|
||||
%if (%superq(packageName) = ) OR (%qupcase(&packageName.) = HELP) %then
|
||||
%do;
|
||||
%local options_tmp ;
|
||||
%let options_tmp = ls=%sysfunc(getoption(ls))ps=%sysfunc(getoption(ps))
|
||||
%sysfunc(getoption(notes)) %sysfunc(getoption(source))
|
||||
msglevel=%sysfunc(getoption(msglevel))
|
||||
;
|
||||
options NOnotes NOsource ls=MAX ps=MAX msglevel=N;
|
||||
%put ;
|
||||
%put #################################################################################;
|
||||
%put ### This is short help information for the `loadPackage` macro #;
|
||||
%put #-------------------------------------------------------------------------------#;
|
||||
%put # #;
|
||||
%put # Macro to *load* SAS packages, version `20231210` #;
|
||||
%put # #;
|
||||
%put # A SAS package is a zip file containing a group #;
|
||||
%put # of SAS codes (macros, functions, data steps generating #;
|
||||
%put # data, etc.) wrapped up together and included by #;
|
||||
%put # a single `load.sas` file (also embedded inside the zip). #;
|
||||
%put # #;
|
||||
%put # The `%nrstr(%%loadPackage())` macro loads package content, i.e. macros, #;
|
||||
%put # functions, formats, etc., from the zip into the SAS session. #;
|
||||
%put # #;
|
||||
%put #-------------------------------------------------------------------------------#;
|
||||
%put #### Parameters: #;
|
||||
%put # #;
|
||||
%put # 1. `packageName` *Required.* Name of a package, e.g. myPackage, #;
|
||||
%put # Required and not null, default use case: #;
|
||||
%put # `%nrstr(%%loadPackage(myPackage)).` #;
|
||||
%put # If empty displays this help information. #;
|
||||
%put # #;
|
||||
%put # - `path=` *Optional.* Location of a package. By default it #;
|
||||
%put # looks for location of the **packages** fileref, i.e. #;
|
||||
%put # `%nrstr(%%sysfunc(pathname(packages)))` #;
|
||||
%put # #;
|
||||
%put # - `options=` *Optional.* Possible options for ZIP filename, #;
|
||||
%put # default value: `LOWCASE_MEMNAME` #;
|
||||
%put # #;
|
||||
%put # - `source2=` *Optional.* Option to print out details about #;
|
||||
%put # what is loaded, null by default. #;
|
||||
%put # #;
|
||||
%put # - `requiredVersion=` *Optional.* Option to test if the loaded #;
|
||||
%put # package is provided in required version, #;
|
||||
%put # default value: `.` #;
|
||||
%put # #;
|
||||
%put # - `lazyData=` *Optional.* A space separated list of names of lazy #;
|
||||
%put # datasets to be loaded. If not null datasets from the #;
|
||||
%put # list are loaded instead of the package. #;
|
||||
%put # An asterisk (*) means *load all lazy datasets*. #;
|
||||
%put # #;
|
||||
%put # - `zip=` *Optional.* Standard package is zip (lowcase), #;
|
||||
%put # e.g. `%nrstr(%%loadPackage(PiPackage))`. #;
|
||||
%put # If the zip is not available use a folder. #;
|
||||
%put # Unpack data to "pipackage.disk" folder #;
|
||||
%put # and use loadPackage in the following form: #;
|
||||
%put # `%nrstr(%%loadPackage(PiPackage, zip=disk, options=))` #;
|
||||
%put # #;
|
||||
%put # - `cherryPick=` *Optional.* A space separated list of selected elements #;
|
||||
%put # of the package to be loaded into the SAS session. #;
|
||||
%put # Default value of an asterisk (*) means: #;
|
||||
%put # "load all elements of the package". #;
|
||||
%put # #;
|
||||
%put # - `loadAddCnt=` *Optional.* A package zip may contain additional #;
|
||||
%put # content. The option indicates if it should be loaded #;
|
||||
%put # Default value of zero (`0`) means "No", one (`1`) #;
|
||||
%put # means "Yes". Content is extracted into the **Work** #;
|
||||
%put # directory in `<packageName>_AdditionalContent` folder. #;
|
||||
%put # For other locations use `%nrstr(%%loadPackageAddCnt())` macro. #;
|
||||
%put # #;
|
||||
%put # - `suppressExec=` *Optional.* Indicates if loading of `exec` type files #;
|
||||
%put # should be suppressed, default value is `0`, #;
|
||||
%put # when set to `1` `exec` files are *not* loaded #;
|
||||
%put # #;
|
||||
%put #-------------------------------------------------------------------------------#;
|
||||
%put # #;
|
||||
%put # Visit: `https://github.com/yabwon/SAS_PACKAGES/tree/main/SPF/Documentation` #;
|
||||
%put # to learn more. #;
|
||||
%put # #;
|
||||
%put ### Example 1 ###################################################################;
|
||||
%put # #;
|
||||
%put # Enabling the SAS Package Framework #;
|
||||
%put # from the local directory and installing & loading #;
|
||||
%put # the SQLinDS package from the Internet. #;
|
||||
%put # #;
|
||||
%put # Assume that the `SPFinit.sas` file #;
|
||||
%put # is located in the "C:/SAS_PACKAGES/" folder. #;
|
||||
%put # #;
|
||||
%put # Run the following code in your SAS session: #;
|
||||
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas;
|
||||
%put %nrstr( filename packages "C:/SAS_PACKAGES"; %%* setup a directory for packages; );
|
||||
%put %nrstr( %%include packages(SPFinit.sas); %%* enable the framework; );
|
||||
%put ;
|
||||
%put %nrstr( %%installPackage(SQLinDS) %%* install the package from the Internet; );
|
||||
%put %nrstr( %%helpPackage(SQLinDS) %%* get help about the package; );
|
||||
%put %nrstr( %%loadPackage(SQLinDS) %%* load the package content into the SAS session; );
|
||||
%put %nrstr( %%unloadPackage(SQLinDS) %%* unload the package content from the SAS session; );
|
||||
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;
|
||||
%put # #;
|
||||
%put ### Example 2 ###################################################################;
|
||||
%put # #;
|
||||
%put # Enabling the SAS Package Framework #;
|
||||
%put # from the local directory and installing & cherry picking #;
|
||||
%put # elements of the BasePlus package. #;
|
||||
%put # #;
|
||||
%put # Assume that the `SPFinit.sas` file #;
|
||||
%put # is located in the "C:/SAS_PACKAGES/" folder. #;
|
||||
%put # #;
|
||||
%put # Run the following code in your SAS session: #;
|
||||
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas;
|
||||
%put %nrstr( filename packages "C:/SAS_PACKAGES"; %%* setup a directory for packages; );
|
||||
%put %nrstr( %%include packages(SPFinit.sas); %%* enable the framework; );
|
||||
%put ;
|
||||
%put %nrstr( %%installPackage(BasePlus) %%* install the package from the Internet; );
|
||||
%put %nrstr( %%loadPackage(BasePlus, cherryPick=getVars) %%* cherry pick the content; );
|
||||
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;
|
||||
%put # #;
|
||||
%put #################################################################################;
|
||||
%put ;
|
||||
options &options_tmp.;
|
||||
%GOTO ENDofloadPackage;
|
||||
%end;
|
||||
/* local variables for options */
|
||||
%local ls_tmp ps_tmp notes_tmp source_tmp stimer_tmp fullstimer_tmp msglevel_tmp;
|
||||
%let ls_tmp = %sysfunc(getoption(ls));
|
||||
%let ps_tmp = %sysfunc(getoption(ps));
|
||||
%let notes_tmp = %sysfunc(getoption(notes));
|
||||
%let source_tmp = %sysfunc(getoption(source));
|
||||
%let stimer_tmp = %sysfunc(getoption(stimer));
|
||||
%let fullstimer_tmp = %sysfunc(getoption(fullstimer));
|
||||
%let msglevel_tmp = %sysfunc(getoption(msglevel));
|
||||
|
||||
options NOnotes NOsource ls=MAX ps=MAX NOfullstimer NOstimer msglevel=N;
|
||||
|
||||
%local _PackageFileref_;
|
||||
/* %let _PackageFileref_ = P%sysfunc(MD5(%lowcase(&packageName.)),hex7.); */
|
||||
data _null_; call symputX("_PackageFileref_", "P" !! put(MD5("%lowcase(&packageName.)"), hex7. -L), "L"); run;
|
||||
|
||||
/* when the packages reference is multi-directory search for the first one containing the package */
|
||||
data _null_;
|
||||
exists = 0;
|
||||
length packages $ 32767 p $ 4096;
|
||||
packages = resolve(symget("path"));
|
||||
if char(packages,1) ^= "(" then packages = quote(strip(packages)); /* for paths with spaces */
|
||||
do i = 1 to kcountw(packages, "()", "QS");
|
||||
p = dequote(kscanx(packages, i, "()", "QS"));
|
||||
exists + fileexist(catx("/", p, "%lowcase(&packageName.).&zip."));
|
||||
if exists then leave;
|
||||
end;
|
||||
if exists then call symputx("path", p, "L");
|
||||
run;
|
||||
|
||||
/* convert cherryPick to lower case if needed */
|
||||
%if NOT (%str(*) = %superq(cherryPick)) %then
|
||||
%do;
|
||||
data _null_;
|
||||
call symputX("cherryPick",lowcase(compbl(compress(symget("cherryPick"),". _","KDA"))),"L");
|
||||
run;
|
||||
%end;
|
||||
/* empty list is equivalent to "*" */
|
||||
%if %superq(cherryPick)= %then
|
||||
%do;
|
||||
%let cherryPick=*;
|
||||
%end;
|
||||
|
||||
%if %superq(loadAddCnt) NE 1 %then
|
||||
%do;
|
||||
%let loadAddCnt = 0;
|
||||
%end;
|
||||
|
||||
%if %superq(suppressExec) NE 1 %then
|
||||
%do;
|
||||
%let suppressExec = 0;
|
||||
%end;
|
||||
|
||||
filename &_PackageFileref_. &ZIP.
|
||||
/* put location of package myPackageFile.zip here */
|
||||
"&path./%lowcase(&packageName.).&zip." %unquote(&options.)
|
||||
;
|
||||
%if %sysfunc(fexist(&_PackageFileref_.)) %then
|
||||
%do;
|
||||
%include &_PackageFileref_.(packagemetadata.sas) / &source2.;
|
||||
filename &_PackageFileref_. clear;
|
||||
|
||||
/* test if required version of package is "good enough" */
|
||||
%local rV pV;
|
||||
%let pV = %sysfunc(compress(&packageVersion.,.,kd));
|
||||
%let pV = %sysevalf((%scan(&pV.,1,.,M)+0)*1e8
|
||||
+ (%scan(&pV.,2,.,M)+0)*1e4
|
||||
+ (%scan(&pV.,3,.,M)+0)*1e0);
|
||||
%let rV = %sysfunc(compress(&requiredVersion.,.,kd));
|
||||
%let rV = %sysevalf((%scan(&rV.,1,.,M)+0)*1e8
|
||||
+ (%scan(&rV.,2,.,M)+0)*1e4
|
||||
+ (%scan(&rV.,3,.,M)+0)*1e0);
|
||||
|
||||
%if %sysevalf(&rV. > &pV.) %then
|
||||
%do;
|
||||
%put ERROR: Package &packageName. will not be loaded!;
|
||||
%put ERROR- Required version is &requiredVersion.;
|
||||
%put ERROR- Provided version is &packageVersion.;
|
||||
%put ERROR- Verify installed version of the package.;
|
||||
%put ERROR- ;
|
||||
%GOTO WrongVersionOFPackage; /*%RETURN;*/
|
||||
%end;
|
||||
|
||||
options ls = &ls_tmp. ps = &ps_tmp. ¬es_tmp. &source_tmp.;
|
||||
filename &_PackageFileref_. &ZIP.
|
||||
"&path./%lowcase(&packageName.).&zip." %unquote(&options.)
|
||||
ENCODING =
|
||||
%if %bquote(&packageEncoding.) NE %then &packageEncoding. ;
|
||||
%else utf8 ;
|
||||
;
|
||||
%if %superq(lazyData) = %then
|
||||
%do;
|
||||
%local tempLoad_minoperator temp_noNotes_etc /* for hiding notes */ ;
|
||||
%let tempLoad_minoperator = %sysfunc(getoption(minoperator));
|
||||
options minoperator; /* MinOperator option is required for cherryPicking to work */
|
||||
%include &_PackageFileref_.(load.sas) / &source2.;
|
||||
options &tempLoad_minoperator.;
|
||||
%if 1 = &loadAddCnt. %then
|
||||
%do;
|
||||
%put; %put - Additional content loading - Start -;
|
||||
%loadPackageAddCnt(&packageName.,
|
||||
path=&path.)
|
||||
%put - Additional content loading - End -;
|
||||
%end;
|
||||
%end;
|
||||
%else
|
||||
%do;
|
||||
%include &_PackageFileref_.(lazydata.sas) / &source2.;
|
||||
%end;
|
||||
|
||||
%end;
|
||||
%else %put ERROR:[&sysmacroname] File "&path./&packageName..&zip." does not exist!;
|
||||
filename &_PackageFileref_. clear;
|
||||
|
||||
%WrongVersionOFPackage:
|
||||
|
||||
/* restore optionos */
|
||||
options ls = &ls_tmp. ps = &ps_tmp.
|
||||
¬es_tmp. &source_tmp.
|
||||
&stimer_tmp. &fullstimer_tmp.
|
||||
msglevel=&msglevel_tmp.;
|
||||
|
||||
%ENDofloadPackage:
|
||||
%mend loadPackage;
|
||||
|
||||
375
SPF/Macros/loadpackageaddcnt.sas
Normal file
375
SPF/Macros/loadpackageaddcnt.sas
Normal file
@@ -0,0 +1,375 @@
|
||||
/*+loadPackageAddCnt+*/
|
||||
/*** HELP START ***/
|
||||
|
||||
%macro loadPackageAddCnt(
|
||||
packageName /* name of a package,
|
||||
e.g. myPackage,
|
||||
required and not null */
|
||||
, path = %sysfunc(pathname(packages)) /* location of a package,
|
||||
by default it looks for
|
||||
location of "packages" fileref */
|
||||
, target = %sysfunc(pathname(WORK)) /* a path in which the directory with
|
||||
additional content will be generated,
|
||||
name of directory created is set to
|
||||
`&packageName._AdditionalContent`
|
||||
default location is SAS work */
|
||||
, source2 = /*source2*/ /* option to print out details,
|
||||
null by default */
|
||||
, requiredVersion = . /* option to test if loaded package
|
||||
is provided in required version */
|
||||
)/secure
|
||||
/*** HELP END ***/
|
||||
des = 'Macro to load additional content for a SAS package, version 20231210. Run %loadPackageAddCnt() for help info.'
|
||||
minoperator
|
||||
;
|
||||
%if (%superq(packageName) = ) OR (%qupcase(&packageName.) = HELP) %then
|
||||
%do;
|
||||
%local options_tmp ;
|
||||
%let options_tmp = ls=%sysfunc(getoption(ls))ps=%sysfunc(getoption(ps))
|
||||
%sysfunc(getoption(notes)) %sysfunc(getoption(source))
|
||||
msglevel=%sysfunc(getoption(msglevel))
|
||||
;
|
||||
options NOnotes NOsource ls=MAX ps=MAX msglevel=N;
|
||||
%put ;
|
||||
%put #################################################################################;
|
||||
%put ### This is short help information for the `loadPackageAddCnt` macro #;
|
||||
%put #-------------------------------------------------------------------------------#;
|
||||
%put # #;
|
||||
%put # Macro to *load* additional content for a SAS package, version `20231210` #;
|
||||
%put # #;
|
||||
%put # A SAS package is a zip file containing a group #;
|
||||
%put # of SAS codes (macros, functions, data steps generating #;
|
||||
%put # data, etc.) wrapped up together and included by #;
|
||||
%put # a single `load.sas` file (also embedded inside the zip). #;
|
||||
%put # #;
|
||||
%put # The `%nrstr(%%loadPackageAddCnt())` macro loads additional content #;
|
||||
%put # for a package (of course only if one is provided). #;
|
||||
%put # #;
|
||||
%put #-------------------------------------------------------------------------------#;
|
||||
%put #### Parameters: #;
|
||||
%put # #;
|
||||
%put # 1. `packageName` *Required.* Name of a package, e.g. myPackage, #;
|
||||
%put # Required and not null, default use case: #;
|
||||
%put # `%nrstr(%%loadPackageAddCnt(myPackage))`. #;
|
||||
%put # If empty displays this help information. #;
|
||||
%put # #;
|
||||
%put # - `path=` *Optional.* Location of a package. By default it #;
|
||||
%put # looks for location of the **packages** fileref, i.e. #;
|
||||
%put # `%nrstr(%%sysfunc(pathname(packages)))` #;
|
||||
%put # #;
|
||||
%put # - `target=` *Optional.* Location where the directory with #;
|
||||
%put # additional content will be generated, #;
|
||||
%put # name of the directory created is set to #;
|
||||
%put # `<packagename>_AdditionalContent`, the default #;
|
||||
%put # location is `%nrstr(%%sysfunc(pathname(WORK)))` #;
|
||||
%put # #;
|
||||
%put # - `source2=` *Optional.* Option to print out details about #;
|
||||
%put # what is loaded, null by default. #;
|
||||
%put # #;
|
||||
%put # - `requiredVersion=` *Optional.* Option to test if the loaded #;
|
||||
%put # package is provided in required version, #;
|
||||
%put # default value: `.` #;
|
||||
%put # #;
|
||||
%put # #;
|
||||
%put #-------------------------------------------------------------------------------#;
|
||||
%put # #;
|
||||
%put # Visit: `https://github.com/yabwon/SAS_PACKAGES/tree/main/SPF/Documentation` #;
|
||||
%put # to learn more. #;
|
||||
%put # #;
|
||||
%put ### Example 1 ###################################################################;
|
||||
%put # #;
|
||||
%put # Enabling the SAS Package Framework #;
|
||||
%put # from the local directory and installing & loading additional content #;
|
||||
%put # for the SQLinDS package. #;
|
||||
%put # #;
|
||||
%put # Assume that the `SPFinit.sas` file #;
|
||||
%put # is located in the "C:/SAS_PACKAGES/" folder. #;
|
||||
%put # #;
|
||||
%put # Run the following code in your SAS session: #;
|
||||
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas;
|
||||
%put %nrstr( filename packages "C:/SAS_PACKAGES"; %%* setup a directory for packages; );
|
||||
%put %nrstr( %%include packages(SPFinit.sas); %%* enable the framework; );
|
||||
%put ;
|
||||
%put %nrstr( %%installPackage(SQLinDS) %%* install the package from the Internet; );
|
||||
%put %nrstr( %%loadPackageAddCnt(SQLinDS) %%* load additional content for the package; );
|
||||
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;
|
||||
%put # #;
|
||||
%put #################################################################################;
|
||||
%put ;
|
||||
options &options_tmp.;
|
||||
%GOTO ENDofloadPackageAddCnt;
|
||||
%end;
|
||||
/* local variables for options */
|
||||
%local ls_tmp ps_tmp notes_tmp source_tmp stimer_tmp fullstimer_tmp msglevel_tmp zip;
|
||||
%let ls_tmp = %sysfunc(getoption(ls));
|
||||
%let ps_tmp = %sysfunc(getoption(ps));
|
||||
%let notes_tmp = %sysfunc(getoption(notes));
|
||||
%let source_tmp = %sysfunc(getoption(source));
|
||||
%let stimer_tmp = %sysfunc(getoption(stimer));
|
||||
%let fullstimer_tmp = %sysfunc(getoption(fullstimer));
|
||||
%let msglevel_tmp = %sysfunc(getoption(msglevel));
|
||||
|
||||
%let zip = zip;
|
||||
|
||||
options NOnotes NOsource ls=MAX ps=MAX NOfullstimer NOstimer msglevel=N;
|
||||
|
||||
%local _PackageFileref_;
|
||||
/* %let _PackageFileref_ = P%sysfunc(MD5(%lowcase(&packageName.)),hex7.); */
|
||||
data _null_;
|
||||
call symputX("_PackageFileref_", "A" !! put(MD5("%lowcase(&packageName.)"), hex7. -L), "L");
|
||||
call symputX("_TargetFileref_", "T" !! put(MD5("%lowcase(&packageName.)"), hex7. -L), "L");
|
||||
run;
|
||||
|
||||
/* when the packages reference is multi-directory search for the first one containing the package */
|
||||
data _null_;
|
||||
exists = 0;
|
||||
length packages $ 32767 p $ 4096;
|
||||
packages = resolve(symget("path"));
|
||||
if char(packages,1) ^= "(" then packages = quote(strip(packages)); /* for paths with spaces */
|
||||
do i = 1 to kcountw(packages, "()", "QS");
|
||||
p = dequote(kscanx(packages, i, "()", "QS"));
|
||||
exists + fileexist(catx("/", p, "%lowcase(&packageName.).&zip."));
|
||||
if exists then leave;
|
||||
end;
|
||||
if exists then call symputx("path", p, "L");
|
||||
run;
|
||||
|
||||
filename &_PackageFileref_. &ZIP.
|
||||
/* put location of package myPackageFile.zip here */
|
||||
"&path./%lowcase(&packageName.).&zip."
|
||||
;
|
||||
%if %sysfunc(fexist(&_PackageFileref_.)) %then
|
||||
%do;
|
||||
|
||||
filename &_PackageFileref_. &ZIP.
|
||||
/* check existence of addcnt.zip inside package */
|
||||
"&path./%lowcase(&packageName.).&zip."
|
||||
member='addcnt.zip'
|
||||
;
|
||||
%if %sysfunc(fexist(&_PackageFileref_.)) %then
|
||||
%do;
|
||||
|
||||
/* get metadata */
|
||||
filename &_PackageFileref_. &ZIP.
|
||||
"&path./%lowcase(&packageName.).&zip."
|
||||
;
|
||||
%include &_PackageFileref_.(packagemetadata.sas) / &source2.;
|
||||
filename &_PackageFileref_. clear;
|
||||
|
||||
/* test if required version of package is "good enough" */
|
||||
%local rV pV;
|
||||
%let pV = %sysfunc(compress(&packageVersion.,.,kd));
|
||||
%let pV = %sysevalf((%scan(&pV.,1,.,M)+0)*1e8
|
||||
+ (%scan(&pV.,2,.,M)+0)*1e4
|
||||
+ (%scan(&pV.,3,.,M)+0)*1e0);
|
||||
%let rV = %sysfunc(compress(&requiredVersion.,.,kd));
|
||||
%let rV = %sysevalf((%scan(&rV.,1,.,M)+0)*1e8
|
||||
+ (%scan(&rV.,2,.,M)+0)*1e4
|
||||
+ (%scan(&rV.,3,.,M)+0)*1e0);
|
||||
|
||||
%if %sysevalf(&rV. > &pV.) %then
|
||||
%do;
|
||||
%put ERROR: Additional content for package &packageName. will not be loaded!;
|
||||
%put ERROR- Required version is &requiredVersion.;
|
||||
%put ERROR- Provided version is &packageVersion.;
|
||||
%put ERROR- Verify installed version of the package.;
|
||||
%put ERROR- ;
|
||||
%GOTO WrongVersionOFPackageAddCnt; /*%RETURN;*/
|
||||
%end;
|
||||
|
||||
/*options ls = &ls_tmp. ps = &ps_tmp. ¬es_tmp. &source_tmp.;*/
|
||||
filename &_PackageFileref_. &ZIP.
|
||||
"&path./%lowcase(&packageName.).&zip."
|
||||
member='addcnt.zip'
|
||||
;
|
||||
/*********************/
|
||||
filename &_TargetFileref_. "&target.";
|
||||
%if %sysfunc(fexist(&_TargetFileref_.)) %then
|
||||
%do;
|
||||
|
||||
%if %sysfunc(fileexist(%sysfunc(pathname(&_TargetFileref_.))/%lowcase(&packageName.)_AdditionalContent)) %then
|
||||
%do; /* dir for AC already exists */
|
||||
%put WARNING: Target location:;
|
||||
%put WARNING- %sysfunc(pathname(&_TargetFileref_.))/%lowcase(&packageName.)_AdditionalContent;
|
||||
%put WARNING- already exist. Please remove it manually to upload additional contents.;
|
||||
%put WARNING- Additional Content will not be loaded.;
|
||||
%put WARNING- ;
|
||||
%end;
|
||||
%else
|
||||
%do;
|
||||
/*-+-+-+-*/
|
||||
/* create target location */
|
||||
%put INFO:;
|
||||
%put Additional content will be located in:;
|
||||
%put %sysfunc(dcreate(%lowcase(&packageName.)_AdditionalContent,%sysfunc(pathname(&_TargetFileref_.))));
|
||||
|
||||
%if NOT (%sysfunc(fileexist(%sysfunc(pathname(&_TargetFileref_.))/%lowcase(&packageName.)_AdditionalContent))) %then
|
||||
%do; /* dir for AC cannot be generated */
|
||||
%put ERROR: Cannot create target location:;
|
||||
%put ERROR- %sysfunc(pathname(&_TargetFileref_.))/%lowcase(&packageName.)_AdditionalContent;
|
||||
%put ERROR- Additional Content will not be loaded.;
|
||||
%put ERROR- ;
|
||||
%end;
|
||||
%else
|
||||
%do;
|
||||
/* extract addcnt.zip to work and, if successful, load additional content */
|
||||
%put NOTE- **%sysfunc(DoSubL(%nrstr(
|
||||
;
|
||||
options nonotes nosource ps=min ls=max;
|
||||
data _null_;
|
||||
call symputx("AdditionalContent", 0, "L");
|
||||
|
||||
rc1=filename("in", pathname("&_PackageFileref_."), "ZIP", "lrecl=1 recfm=n member='addcnt.zip'");
|
||||
length rc1txt $ 8192;
|
||||
rc1txt=sysmsg();
|
||||
|
||||
if fexist("in") then
|
||||
do;
|
||||
rc2=filename("out", pathname("WORK")!!"/%lowcase(&packageName.)addcnt.zip", "disk", "lrecl=1 recfm=n");
|
||||
length rc2txt $ 8192;
|
||||
rc2txt=sysmsg();
|
||||
|
||||
rc3=fcopy("in","out");
|
||||
length rc3txt $ 8192;
|
||||
rc3txt=sysmsg();
|
||||
|
||||
if rc3 then put _N_ @12 (rc:) (=);
|
||||
|
||||
if fexist("out") then
|
||||
do;
|
||||
call symputx("AdditionalContent", 1, "L");
|
||||
end;
|
||||
else put "INFO: No additional content for package &packageName..";
|
||||
|
||||
rc1=filename("in");
|
||||
rc2=filename("out");
|
||||
end;
|
||||
else
|
||||
do;
|
||||
call symputx("AdditionalContent", 0, "L");
|
||||
put "INFO: No additional content for package &packageName..";
|
||||
end;
|
||||
run;
|
||||
|
||||
%if &AdditionalContent. %then
|
||||
%do;
|
||||
filename f DUMMY;
|
||||
filename f ZIP "%sysfunc(pathname(WORK))/%lowcase(&packageName.)addcnt.zip";
|
||||
options dlCreateDir;
|
||||
libname outData "%sysfunc(pathname(&_TargetFileref_.))/%lowcase(&packageName.)_AdditionalContent";
|
||||
|
||||
data WORK.__&_TargetFileref_._zip___;
|
||||
did = dopen("f");
|
||||
if not did then
|
||||
do;
|
||||
put "ERROR: Can not access Additional Content data.";
|
||||
stop;
|
||||
end;
|
||||
if did then
|
||||
do i=1 to dnum(did);
|
||||
length file $ 8192;
|
||||
file = dread(did, i);
|
||||
output;
|
||||
keep file;
|
||||
end;
|
||||
did = dclose(did);
|
||||
run;
|
||||
|
||||
data _null_;
|
||||
set WORK.__&_TargetFileref_._zip___ end = EOF;
|
||||
wc = countw(file,"/\");
|
||||
|
||||
length libText pathname_f $ 8192;
|
||||
libText = pathname("outData", "L");
|
||||
|
||||
if scan(file, wc , "/\") = "" then
|
||||
do j = 1 to wc-1;
|
||||
libText = catx("/", libText, scan(file, j , "/\"));
|
||||
rc = libname("test", libText);
|
||||
rc = libname("test");
|
||||
end;
|
||||
else
|
||||
do;
|
||||
do j = 1 to wc-1;
|
||||
libText = catx("/", libText, scan(file, j , "/\"));
|
||||
rc = libname("test", libText);
|
||||
rc = libname("test");
|
||||
end;
|
||||
|
||||
pathname_f = pathname("f");
|
||||
rc1 = filename("in", strip(pathname_f), "zip", "member='" !! strip(file) !! "' lrecl=1 recfm=n");
|
||||
length rc1msg $ 8192;
|
||||
rc1msg = sysmsg();
|
||||
rc2 = filename("out", catx("/", libText, scan(file, j , "/\")), "disk", "lrecl=1 recfm=n");
|
||||
length rc2msg $ 8192;
|
||||
rc2msg = sysmsg();
|
||||
|
||||
rc3 = fcopy("in", "out");
|
||||
length rc3msg $ 8192;
|
||||
rc3msg = sysmsg();
|
||||
|
||||
loadingProblem + (rc3 & 1);
|
||||
|
||||
if rc3 then
|
||||
do;
|
||||
put "ERROR: Cannot extract: " file;
|
||||
put (rc1 rc2 rc3) (=);
|
||||
put (rc1msg rc2msg rc3msg) (/);
|
||||
put "ERROR-";
|
||||
end;
|
||||
crc1=filename("in");
|
||||
crc2=filename("out");
|
||||
end;
|
||||
|
||||
if EOF and loadingProblem then
|
||||
do;
|
||||
put "ERROR: Not all files from Additional Content were extracted successfully!";
|
||||
end;
|
||||
run;
|
||||
|
||||
data _null_;
|
||||
rc = fdelete("f");
|
||||
run;
|
||||
|
||||
proc delete data = WORK.__&_TargetFileref_._zip___;
|
||||
run;
|
||||
|
||||
libname outData;
|
||||
filename f DUMMY;
|
||||
%end;
|
||||
)))**;
|
||||
%end;
|
||||
/*-+-+-+-*/
|
||||
%end;
|
||||
|
||||
%end;
|
||||
%else
|
||||
%do;
|
||||
%put ERROR: Cannot access target location:;
|
||||
%put ERROR- %sysfunc(pathname(&_TargetFileref_.));
|
||||
%put ERROR- Additional Content will not be loaded.;
|
||||
%put ERROR- ;
|
||||
%end;
|
||||
filename &_TargetFileref_. clear;
|
||||
/*********************/
|
||||
%end;
|
||||
%else %put INFO: No additional content for &packageName. package.;
|
||||
%end;
|
||||
%else %put ERROR:[&sysmacroname] File "&path./&packageName..&zip." does not exist!;
|
||||
filename &_PackageFileref_. clear;
|
||||
|
||||
%WrongVersionOFPackageAddCnt:
|
||||
|
||||
/* restore optionos */
|
||||
options ls = &ls_tmp. ps = &ps_tmp.
|
||||
¬es_tmp. &source_tmp.
|
||||
&stimer_tmp. &fullstimer_tmp.
|
||||
msglevel=&msglevel_tmp.;
|
||||
|
||||
%ENDofloadPackageAddCnt:
|
||||
%mend loadPackageAddCnt;
|
||||
|
||||
|
||||
|
||||
|
||||
/**/
|
||||
111
SPF/Macros/loadpackages.sas
Normal file
111
SPF/Macros/loadpackages.sas
Normal file
@@ -0,0 +1,111 @@
|
||||
/*+loadPackageS+*/
|
||||
/*** HELP START ***/
|
||||
|
||||
%macro loadPackageS(
|
||||
packagesNames /* A comma separated list of packages names,
|
||||
e.g. myPackage, myPackage1, myPackage2, myPackage3
|
||||
required and not null.
|
||||
Package version, in brackets behind a package name,
|
||||
can be provided, e.g.
|
||||
%loadPackageS(myPackage1(1.7), myPackage2(4.2))
|
||||
*/
|
||||
)/secure
|
||||
/*** HELP END ***/
|
||||
des = 'Macro to load multiple SAS packages at one run, version 20231210. Run %loadPackages() for help info.'
|
||||
parmbuff
|
||||
;
|
||||
%if (%superq(packagesNames) = ) OR (%qupcase(&packagesNames.) = HELP) %then
|
||||
%do;
|
||||
%local options_tmp ;
|
||||
%let options_tmp = ls=%sysfunc(getoption(ls))ps=%sysfunc(getoption(ps))
|
||||
%sysfunc(getoption(notes)) %sysfunc(getoption(source))
|
||||
msglevel=%sysfunc(getoption(msglevel))
|
||||
;
|
||||
options NOnotes NOsource ls=MAX ps=MAX msglevel=N;
|
||||
%put ;
|
||||
%put #################################################################################;
|
||||
%put ### This is short help information for the `loadPackageS` macro #;
|
||||
%put #-------------------------------------------------------------------------------#;
|
||||
%put # #;
|
||||
%put # Macro wrapper for the loadPackage macro, version `20231210` #;
|
||||
%put # #;
|
||||
%put # A SAS package is a zip file containing a group #;
|
||||
%put # of SAS codes (macros, functions, data steps generating #;
|
||||
%put # data, etc.) wrapped up together and embedded inside the zip. #;
|
||||
%put # #;
|
||||
%put # The `%nrstr(%%loadPackageS())` allows to load multiple packages at one time, #;
|
||||
%put # *ONLY* from the *ZIP* with *DEFAULT OPTIONS*, into the SAS session. #;
|
||||
%put # #;
|
||||
%put #### Parameters: #;
|
||||
%put # #;
|
||||
%put # 1. `packagesNames` A comma separated list of packages names, #;
|
||||
%put # e.g. myPackage, myPackage1, myPackage2, myPackage3 #;
|
||||
%put # Required and not null, default use case: #;
|
||||
%put # `%nrstr(%%loadPackageS(myPackage1, myPackage2, myPackage3))`. #;
|
||||
%put # Package version, in brackets behind a package name, can #;
|
||||
%put # be provided, example is the following: #;
|
||||
%put # `%nrstr(%%loadPackageS(myPackage1(1.7), myPackage2(4.2)))`. #;
|
||||
%put # If empty displays this help information. #;
|
||||
%put # #;
|
||||
%put # #;
|
||||
%put #-------------------------------------------------------------------------------#;
|
||||
%put # #;
|
||||
%put # Visit: `https://github.com/yabwon/SAS_PACKAGES/tree/main/SPF/Documentation` #;
|
||||
%put # to learn more. #;
|
||||
%put # #;
|
||||
%put #### Example ####################################################################;
|
||||
%put # #;
|
||||
%put # Enabling the SAS Package Framework #;
|
||||
%put # from the local directory and installing & loading #;
|
||||
%put # the SQLinDS package from the Internet. #;
|
||||
%put # #;
|
||||
%put # Assume that the `SPFinit.sas` file #;
|
||||
%put # is located in the "C:/SAS_PACKAGES/" folder. #;
|
||||
%put # #;
|
||||
%put # Run the following code in your SAS session: #;
|
||||
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas;
|
||||
%put %nrstr( filename packages "C:/SAS_PACKAGES"; %%* setup a directory for packages; );
|
||||
%put %nrstr( %%include packages(SPFinit.sas); %%* enable the framework; );
|
||||
%put ;
|
||||
%put %nrstr( %%installPackage(SQLinDS DFA) %%* install packages from the Internet; );
|
||||
%put %nrstr( %%loadPackageS(SQLinDS, DFA) %%* load packages content into the SAS session; );
|
||||
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;
|
||||
%put #################################################################################;
|
||||
%put ;
|
||||
options &options_tmp.;
|
||||
%GOTO ENDofloadPackageS;
|
||||
%end;
|
||||
|
||||
%local lengthOfsyspbuff numberOfPackagesNames i packageElement packageName packageVersion str;
|
||||
|
||||
%let lengthOfsyspbuff = %qsysfunc(length(&syspbuff.));
|
||||
%let packagesNames = %qsysfunc(compress(%qsubstr(&syspbuff., 2, %eval(&lengthOfsyspbuff.-2)), {[(. _,)]}, KDA));
|
||||
|
||||
%let str = %qsysfunc(translate(%superq(packagesNames),[[ ]],{(,)}));
|
||||
%let str = %qsysfunc(transtrn(%superq(str),],%str(] )));
|
||||
%let str = %qsysfunc(compbl(%superq(str)));
|
||||
%let str = %qsysfunc(transtrn(%superq(str),%str([ ),[));
|
||||
%let str = %qsysfunc(transtrn(%superq(str),%str( [),[));
|
||||
%let str = %qsysfunc(transtrn(%superq(str),%str( ]),]));
|
||||
%let str = %qsysfunc(translate(%superq(str),(),[]));
|
||||
%let packagesNames = %unquote(&str.);
|
||||
|
||||
%let numberOfPackagesNames = %qsysfunc(countw(&packagesNames., %str( )));
|
||||
|
||||
%put NOTE: List of packages to be loaded contains &numberOfPackagesNames. element(s).;
|
||||
%put NOTE- The list is: &packagesNames..;
|
||||
%put NOTE- ;
|
||||
|
||||
%do i = 1 %to &numberOfPackagesNames.;
|
||||
%let packageElement = %qscan(&packagesNames., &i., %str( ) );
|
||||
%let packageName = %qscan(&packageElement., 1, %str(()));
|
||||
%let packageVersion = %qscan(&packageElement., 2, %str(()));
|
||||
%if %superq(packageVersion) = %then %let packageVersion = .;
|
||||
|
||||
%loadPackage(%unquote(&packageName.), requiredVersion=%unquote(&packageVersion.))
|
||||
%end;
|
||||
|
||||
%ENDofloadPackageS:
|
||||
%mend loadPackageS;
|
||||
|
||||
|
||||
159
SPF/Macros/previewpackage.sas
Normal file
159
SPF/Macros/previewpackage.sas
Normal file
@@ -0,0 +1,159 @@
|
||||
/*+previewPackage+*/
|
||||
/*** HELP START ***/
|
||||
|
||||
%macro previewPackage(
|
||||
packageName /* name of a package,
|
||||
e.g. myPackageFile.zip,
|
||||
required and not null */
|
||||
, helpKeyword /* phrase to search for preview,
|
||||
when empty prints description
|
||||
"*" means prints all */
|
||||
, path = %sysfunc(pathname(packages)) /* location of a package,
|
||||
by default it looks for
|
||||
location of "packages" fileref */
|
||||
, options = %str(LOWCASE_MEMNAME) /* possible options for ZIP filename */
|
||||
, source2 = /*source2*/ /* option to print out details,
|
||||
null by default */
|
||||
, zip = zip /* standard package is zip (lowcase),
|
||||
e.g. %previewPackage(PiPackage,*)
|
||||
if the zip is not available use a folder
|
||||
unpack data to "pipackage.disk" folder
|
||||
and use previewPackage in the form:
|
||||
%previewPackage(PiPackage, *, zip=disk, options=)
|
||||
*/
|
||||
)/secure
|
||||
/*** HELP END ***/
|
||||
des = 'Macro to preview content of a SAS package, version 20231210. Run %previewPackage() for help info.'
|
||||
;
|
||||
%if (%superq(packageName) = ) OR (%qupcase(&packageName.) = HELP) %then
|
||||
%do;
|
||||
%local options_tmp ;
|
||||
%let options_tmp = ls=%sysfunc(getoption(ls))ps=%sysfunc(getoption(ps))
|
||||
%sysfunc(getoption(notes)) %sysfunc(getoption(source))
|
||||
msglevel=%sysfunc(getoption(msglevel))
|
||||
;
|
||||
options NOnotes NOsource ls=MAX ps=MAX msglevel=N;
|
||||
%put ;
|
||||
%put #################################################################################;
|
||||
%put ### This is short help information for the `previewPackage` macro #;
|
||||
%put #-------------------------------------------------------------------------------#;
|
||||
%put # #;
|
||||
%put # Macro to get previwe of a SAS packages, version `20231210` #;
|
||||
%put # #;
|
||||
%put # A SAS package is a zip file containing a group #;
|
||||
%put # of SAS codes (macros, functions, data steps generating #;
|
||||
%put # data, etc.) wrapped up together and provided with #;
|
||||
%put # a single `preview.sas` file (also embedded inside the zip). #;
|
||||
%put # #;
|
||||
%put # The `%nrstr(%%previewPackage())` macro prints, in the SAS log, content #;
|
||||
%put # of a SAS package. Code of a package is printed out. #;
|
||||
%put # #;
|
||||
%put #-------------------------------------------------------------------------------#;
|
||||
%put # #;
|
||||
%put #### Parameters: #;
|
||||
%put # #;
|
||||
%put # 1. `packageName` *Required.* Name of a package, e.g. myPackage, #;
|
||||
%put # Required and not null, default use case: #;
|
||||
%put # `%nrstr(%%previewPackage(myPackage)).` #;
|
||||
%put # If empty displays this help information. #;
|
||||
%put # #;
|
||||
%put # 2. `helpKeyword` *Optional.* A phrase to search in preview, #;
|
||||
%put # - when empty prints description, #;
|
||||
%put # - "*" means: print all preview. #;
|
||||
%put # #;
|
||||
%put # - `path=` *Optional.* Location of a package. By default it #;
|
||||
%put # looks for location of the **packages** fileref, i.e. #;
|
||||
%put # `%nrstr(%%sysfunc(pathname(packages)))` #;
|
||||
%put # #;
|
||||
%put # - `options=` *Optional.* Possible options for ZIP filename, #;
|
||||
%put # default value: `LOWCASE_MEMNAME` #;
|
||||
%put # #;
|
||||
%put # - `source2=` *Optional.* Option to print out details about #;
|
||||
%put # what is loaded, null by default. #;
|
||||
%put # #;
|
||||
%put # - `zip=` Standard package is zip (lowcase), #;
|
||||
%put # e.g. `%nrstr(%%previewPackage(PiPackage))`. #;
|
||||
%put # If the zip is not available use a folder. #;
|
||||
%put # Unpack data to "pipackage.disk" folder #;
|
||||
%put # and use previewPackage in the following form: #;
|
||||
%put # `%nrstr(%%previewPackage(PiPackage, , zip=disk, options=))` #;
|
||||
%put # #;
|
||||
%put #-------------------------------------------------------------------------------#;
|
||||
%put # #;
|
||||
%put # Visit: `https://github.com/yabwon/SAS_PACKAGES/tree/main/SPF/Documentation` #;
|
||||
%put # to learn more. #;
|
||||
%put # #;
|
||||
%put #### Example ####################################################################;
|
||||
%put # #;
|
||||
%put # Enabling the SAS Package Framework #;
|
||||
%put # from the local directory and installing & loading #;
|
||||
%put # the SQLinDS package from the Internet. #;
|
||||
%put # #;
|
||||
%put # Assume that the `SPFinit.sas` file #;
|
||||
%put # is located in the "C:/SAS_PACKAGES/" folder. #;
|
||||
%put # #;
|
||||
%put # Run the following code in your SAS session: #;
|
||||
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas;
|
||||
%put %nrstr( filename packages "C:/SAS_PACKAGES"; %%* setup a directory for packages; );
|
||||
%put %nrstr( %%include packages(SPFinit.sas); %%* enable the framework; );
|
||||
%put ;
|
||||
%put %nrstr( %%installPackage(SQLinDS) %%* install the package from the Internet; );
|
||||
%put %nrstr( %%previewPackage(SQLinDS) %%* get content of the package; );
|
||||
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;
|
||||
%put #################################################################################;
|
||||
%put ;
|
||||
options &options_tmp.;
|
||||
%GOTO ENDofpreviewPackage;
|
||||
%end;
|
||||
|
||||
%local ls_tmp ps_tmp notes_tmp source_tmp msglevel_tmp;
|
||||
%let ls_tmp = %sysfunc(getoption(ls));
|
||||
%let ps_tmp = %sysfunc(getoption(ps));
|
||||
%let notes_tmp = %sysfunc(getoption(notes));
|
||||
%let source_tmp = %sysfunc(getoption(source));
|
||||
%let msglevel_tmp = %sysfunc(getoption(msglevel));
|
||||
options NOnotes NOsource ls=MAX ps=MAX msglevel=N;
|
||||
|
||||
%local _PackageFileref_;
|
||||
/* %let _PackageFileref_ = P%sysfunc(MD5(%lowcase(&packageName.)),hex7.); */
|
||||
data _null_; call symputX("_PackageFileref_", "P" !! put(MD5("%lowcase(&packageName.)"), hex7. -L), "L"); run;
|
||||
|
||||
/* when the packages reference is multi-directory search for the first one containing the package */
|
||||
data _null_;
|
||||
exists = 0;
|
||||
length packages $ 32767 p $ 4096;
|
||||
packages = resolve(symget("path"));
|
||||
if char(packages,1) ^= "(" then packages = quote(strip(packages)); /* for paths with spaces */
|
||||
do i = 1 to kcountw(packages, "()", "QS");
|
||||
p = dequote(kscanx(packages, i, "()", "QS"));
|
||||
exists + fileexist(catx("/", p, "%lowcase(&packageName.).&zip."));
|
||||
if exists then leave;
|
||||
end;
|
||||
if exists then call symputx("path", p, "L");
|
||||
run;
|
||||
|
||||
filename &_PackageFileref_. &ZIP.
|
||||
/* put location of package myPackageFile.zip here */
|
||||
"&path./%lowcase(&packageName.).&zip." %unquote(&options.)
|
||||
;
|
||||
%if %sysfunc(fexist(&_PackageFileref_.)) %then
|
||||
%do;
|
||||
%include &_PackageFileref_.(packagemetadata.sas) / &source2.;
|
||||
filename &_PackageFileref_. clear;
|
||||
options ls = &ls_tmp. ps = &ps_tmp. ¬es_tmp. &source_tmp.;
|
||||
filename &_PackageFileref_. &ZIP.
|
||||
"&path./%lowcase(&packageName.).&zip." %unquote(&options.)
|
||||
ENCODING =
|
||||
%if %bquote(&packageEncoding.) NE %then &packageEncoding. ;
|
||||
%else utf8 ;
|
||||
;
|
||||
%include &_PackageFileref_.(preview.sas) / &source2.;
|
||||
%end;
|
||||
%else %put ERROR:[&sysmacroname] File "&path./&packageName..&zip." does not exist!;
|
||||
filename &_PackageFileref_. clear;
|
||||
|
||||
options ls = &ls_tmp. ps = &ps_tmp. ¬es_tmp. &source_tmp. msglevel = &msglevel_tmp.;
|
||||
|
||||
%ENDofpreviewPackage:
|
||||
%mend previewPackage;
|
||||
|
||||
156
SPF/Macros/unloadpackage.sas
Normal file
156
SPF/Macros/unloadpackage.sas
Normal file
@@ -0,0 +1,156 @@
|
||||
/*+unloadPackage+*/
|
||||
/*** HELP START ***/
|
||||
|
||||
%macro unloadPackage(
|
||||
packageName /* name of a package,
|
||||
e.g. myPackage,
|
||||
required and not null */
|
||||
, path = %sysfunc(pathname(packages)) /* location of a package,
|
||||
by default it looks for
|
||||
location of "packages" fileref */
|
||||
, options = %str(LOWCASE_MEMNAME) /* possible options for ZIP filename */
|
||||
, source2 = /*source2*/ /* option to print out details,
|
||||
null by default */
|
||||
, zip = zip /* standard package is zip (lowcase),
|
||||
e.g. %unloadPackage(PiPackage)
|
||||
if the zip is not available use a folder
|
||||
unpack data to "pipackage.disk" folder
|
||||
and use unloadPackage in the form:
|
||||
%unloadPackage(PiPackage, zip=disk, options=)
|
||||
*/
|
||||
)/secure
|
||||
/*** HELP END ***/
|
||||
des = 'Macro to unload SAS package, version 20231210. Run %unloadPackage() for help info.'
|
||||
;
|
||||
%if (%superq(packageName) = ) OR (%qupcase(&packageName.) = HELP) %then
|
||||
%do;
|
||||
%local options_tmp ;
|
||||
%let options_tmp = ls=%sysfunc(getoption(ls))ps=%sysfunc(getoption(ps))
|
||||
%sysfunc(getoption(notes)) %sysfunc(getoption(source))
|
||||
msglevel=%sysfunc(getoption(msglevel))
|
||||
;
|
||||
options NOnotes NOsource ls=MAX ps=MAX msglevel=N;
|
||||
%put ;
|
||||
%put #################################################################################;
|
||||
%put ### This is short help information for the `unloadPackage` macro #;
|
||||
%put #-------------------------------------------------------------------------------#;
|
||||
%put # #;
|
||||
%put # Macro to unload SAS packages, version `20231210` #;
|
||||
%put # #;
|
||||
%put # A SAS package is a zip file containing a group #;
|
||||
%put # of SAS codes (macros, functions, data steps generating #;
|
||||
%put # data, etc.) wrapped up together and provided with #;
|
||||
%put # a single `unload.sas` file (also embedded inside the zip). #;
|
||||
%put # #;
|
||||
%put # The `%nrstr(%%unloadPackage())` macro clears the package content #;
|
||||
%put # from the SAS session. #;
|
||||
%put # #;
|
||||
%put #-------------------------------------------------------------------------------#;
|
||||
%put # #;
|
||||
%put #### Parameters: #;
|
||||
%put # #;
|
||||
%put # 1. `packageName` *Required.* Name of a package, e.g. myPackage, #;
|
||||
%put # Required and not null, default use case: #;
|
||||
%put # `%nrstr(%%unloadPackage(myPackage)).` #;
|
||||
%put # If empty displays this help information. #;
|
||||
%put # #;
|
||||
%put # - `path=` *Optional.* Location of a package. By default it #;
|
||||
%put # looks for location of the **packages** fileref, i.e. #;
|
||||
%put # `%nrstr(%%sysfunc(pathname(packages)))` #;
|
||||
%put # #;
|
||||
%put # - `options=` *Optional.* Possible options for ZIP filename, #;
|
||||
%put # default value: `LOWCASE_MEMNAME` #;
|
||||
%put # #;
|
||||
%put # - `source2=` *Optional.* Option to print out details about #;
|
||||
%put # what is loaded, null by default. #;
|
||||
%put # #;
|
||||
%put # - `zip=` Standard package is zip (lowcase), #;
|
||||
%put # e.g. `%nrstr(%%unloadPackage(PiPackage))`. #;
|
||||
%put # If the zip is not available use a folder. #;
|
||||
%put # Unpack data to "pipackage.disk" folder #;
|
||||
%put # and use unloadPackage in the following form: #;
|
||||
%put # `%nrstr(%%unloadPackage(PiPackage, zip=disk, options=))` #;
|
||||
%put # #;
|
||||
%put #-------------------------------------------------------------------------------#;
|
||||
%put # #;
|
||||
%put # Visit: `https://github.com/yabwon/SAS_PACKAGES/tree/main/SPF/Documentation` #;
|
||||
%put # to learn more. #;
|
||||
%put # #;
|
||||
%put ### Example #####################################################################;
|
||||
%put # #;
|
||||
%put # Enabling the SAS Package Framework #;
|
||||
%put # from the local directory and installing & loading #;
|
||||
%put # the SQLinDS package from the Internet. #;
|
||||
%put # #;
|
||||
%put # Assume that the `SPFinit.sas` file #;
|
||||
%put # is located in the "C:/SAS_PACKAGES/" folder. #;
|
||||
%put # #;
|
||||
%put # Run the following code in your SAS session: #;
|
||||
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas;
|
||||
%put %nrstr( filename packages "C:/SAS_PACKAGES"; %%* setup a directory for packages; );
|
||||
%put %nrstr( %%include packages(SPFinit.sas); %%* enable the framework; );
|
||||
%put ;
|
||||
%put %nrstr( %%installPackage(SQLinDS) %%* install the package from the Internet; );
|
||||
%put %nrstr( %%helpPackage(SQLinDS) %%* get help about the package; );
|
||||
%put %nrstr( %%loadPackage(SQLinDS) %%* load the package content into the SAS session; );
|
||||
%put %nrstr( %%unloadPackage(SQLinDS) %%* unload the package content from the SAS session; );
|
||||
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;
|
||||
%put #################################################################################;
|
||||
%put ;
|
||||
options &options_tmp.;
|
||||
%GOTO ENDofunloadPackage;
|
||||
%end;
|
||||
|
||||
/* local variables for options */
|
||||
%local ls_tmp ps_tmp notes_tmp source_tmp msglevel_tmp;
|
||||
%let ls_tmp = %sysfunc(getoption(ls));
|
||||
%let ps_tmp = %sysfunc(getoption(ps));
|
||||
%let notes_tmp = %sysfunc(getoption(notes));
|
||||
%let source_tmp = %sysfunc(getoption(source));
|
||||
%let msglevel_tmp = %sysfunc(getoption(msglevel));
|
||||
|
||||
options NOnotes NOsource ls=MAX ps=MAX msglevel=N;
|
||||
|
||||
%local _PackageFileref_;
|
||||
/* %let _PackageFileref_ = P%sysfunc(MD5(%lowcase(&packageName.)),hex7.); */
|
||||
data _null_; call symputX("_PackageFileref_", "P" !! put(MD5("%lowcase(&packageName.)"), hex7. -L), "L"); run;
|
||||
|
||||
/* when the packages reference is multi-directory search for the first one containing the package */
|
||||
data _null_;
|
||||
exists = 0;
|
||||
length packages $ 32767 p $ 4096;
|
||||
packages = resolve(symget("path"));
|
||||
if char(packages,1) ^= "(" then packages = quote(strip(packages)); /* for paths with spaces */
|
||||
do i = 1 to kcountw(packages, "()", "QS");
|
||||
p = dequote(kscanx(packages, i, "()", "QS"));
|
||||
exists + fileexist(catx("/", p, "%lowcase(&packageName.).&zip."));
|
||||
if exists then leave;
|
||||
end;
|
||||
if exists then call symputx("path", p, "L");
|
||||
run;
|
||||
|
||||
filename &_PackageFileref_. &ZIP.
|
||||
/* put location of package myPackageFile.zip here */
|
||||
"&path./%lowcase(&packageName.).&zip." %unquote(&options.)
|
||||
;
|
||||
%if %sysfunc(fexist(&_PackageFileref_.)) %then
|
||||
%do;
|
||||
%include &_PackageFileref_.(packagemetadata.sas) / &source2.;
|
||||
filename &_PackageFileref_. clear;
|
||||
options ls = &ls_tmp. ps = &ps_tmp. ¬es_tmp. &source_tmp.;
|
||||
filename &_PackageFileref_. &ZIP.
|
||||
"&path./%lowcase(&packageName.).&zip." %unquote(&options.)
|
||||
ENCODING =
|
||||
%if %bquote(&packageEncoding.) NE %then &packageEncoding. ;
|
||||
%else utf8 ;
|
||||
;
|
||||
%include &_PackageFileref_.(unload.sas) / &source2.;
|
||||
%end;
|
||||
%else %put ERROR:[&sysmacroname] File "&path./&packageName..&zip." does not exist!;
|
||||
filename &_PackageFileref_. clear;
|
||||
|
||||
options ls = &ls_tmp. ps = &ps_tmp. ¬es_tmp. &source_tmp. msglevel = &msglevel_tmp.;
|
||||
|
||||
%ENDofunloadPackage:
|
||||
%mend unloadPackage;
|
||||
|
||||
184
SPF/Macros/verifypackage.sas
Normal file
184
SPF/Macros/verifypackage.sas
Normal file
@@ -0,0 +1,184 @@
|
||||
/*+verifyPackage+*/
|
||||
/*** HELP START ***/
|
||||
|
||||
%macro verifyPackage(
|
||||
packageName /* name of a package,
|
||||
e.g. myPackage,
|
||||
required and not null */
|
||||
, path = %sysfunc(pathname(packages)) /* location of a package,
|
||||
by default it looks for
|
||||
location of "packages" fileref */
|
||||
, hash = /* The SHA256 hash digest for
|
||||
the package generated by
|
||||
hashing_file() function, SAS 9.4M6 */
|
||||
)/secure
|
||||
/*** HELP END ***/
|
||||
des = 'Macro to verify SAS package with the hash digest, version 20231210. Run %verifyPackage() for help info.'
|
||||
;
|
||||
%if (%superq(packageName) = ) OR (%qupcase(&packageName.) = HELP) %then
|
||||
%do;
|
||||
%local options_tmp ;
|
||||
%let options_tmp = ls=%sysfunc(getoption(ls))ps=%sysfunc(getoption(ps))
|
||||
%sysfunc(getoption(notes)) %sysfunc(getoption(source))
|
||||
msglevel=%sysfunc(getoption(msglevel))
|
||||
;
|
||||
options NOnotes NOsource ls=MAX ps=MAX msglevel=N;
|
||||
%put ;
|
||||
%put #################################################################################;
|
||||
%put ### This is short help information for the `verifyPackage` macro #;
|
||||
%put #-------------------------------------------------------------------------------#;
|
||||
%put # #;
|
||||
%put # Macro to verify SAS package with it hash digest, version `20231210` #;
|
||||
%put # #;
|
||||
%put # A SAS package is a zip file containing a group #;
|
||||
%put # of SAS codes (macros, functions, data steps generating #;
|
||||
%put # data, etc.) wrapped up together and embedded inside the zip. #;
|
||||
%put # #;
|
||||
%put # The `%nrstr(%%verifyPackage())` macro generate package SHA256 hash #;
|
||||
%put # and compares it with the one provided by the user. #;
|
||||
%put # #;
|
||||
%put # #;
|
||||
%put # *Minimum SAS version required for the process is 9.4M6.* #;
|
||||
%put # #;
|
||||
%put #### Parameters: #;
|
||||
%put # #;
|
||||
%put # 1. `packageName` Name of a package, e.g. myPackage, #;
|
||||
%put # Required and not null, default use case: #;
|
||||
%put # `%nrstr(%%loadPackage(myPackage))`. #;
|
||||
%put # If empty displays this help information. #;
|
||||
%put # #;
|
||||
%put # - `hash=` A value of the package `SHA256` hash. #;
|
||||
%put # Provided by the user. #;
|
||||
%put # #;
|
||||
%put # - `path=` Location of a package. By default it looks for #;
|
||||
%put # location of the "packages" fileref, i.e. #;
|
||||
%put # `%nrstr(%%sysfunc(pathname(packages)))` #;
|
||||
%put # #;
|
||||
%put #-------------------------------------------------------------------------------#;
|
||||
%put # #;
|
||||
%put # Visit: `https://github.com/yabwon/SAS_PACKAGES/tree/main/SPF/Documentation` #;
|
||||
%put # to learn more. #;
|
||||
%put # #;
|
||||
%put #### Example ####################################################################;
|
||||
%put # #;
|
||||
%put # Enabling the SAS Package Framework #;
|
||||
%put # from the local directory and installing & loading #;
|
||||
%put # the SQLinDS package from the Internet. #;
|
||||
%put # #;
|
||||
%put # Assume that the `SPFinit.sas` file #;
|
||||
%put # is located in the "C:/SAS_PACKAGES/" folder. #;
|
||||
%put # #;
|
||||
%put # Run the following code in your SAS session: #;
|
||||
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas;
|
||||
%put %nrstr( filename packages "C:/SAS_PACKAGES"; %%* set-up a directory for packages; );
|
||||
%put %nrstr( %%include packages(SPFinit.sas); %%* enable the framework; );
|
||||
%put ;
|
||||
%put %nrstr( %%installPackage(SQLinDS) %%* install the package from the Internet; );
|
||||
%put %nrstr( %%verifyPackage%(SQLinDS, %%* verify the package with provided hash; );
|
||||
%put %nrstr( hash=HDA478ANJ3HKHRY327FGE88HF89VH89HFFFV73GCV98RF390VB4%) );
|
||||
%put ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;
|
||||
%put #################################################################################;
|
||||
%put ;
|
||||
options &options_tmp.;
|
||||
%GOTO ENDofverifyPackage;
|
||||
%end;
|
||||
|
||||
%local ls_tmp ps_tmp notes_tmp source_tmp stimer_tmp fullstimer_tmp msglevel_tmp;
|
||||
%let ls_tmp = %sysfunc(getoption(ls));
|
||||
%let ps_tmp = %sysfunc(getoption(ps));
|
||||
%let notes_tmp = %sysfunc(getoption(notes));
|
||||
%let source_tmp = %sysfunc(getoption(source));
|
||||
%let stimer_tmp = %sysfunc(getoption(stimer));
|
||||
%let fullstimer_tmp = %sysfunc(getoption(fullstimer));
|
||||
%let msglevel_tmp = %sysfunc(getoption(msglevel));
|
||||
|
||||
options NOnotes NOsource ls=MAX ps=MAX NOfullstimer NOstimer msglevel=N;
|
||||
|
||||
%local _PackageFileref_;
|
||||
/* %let _PackageFileref_ = P%sysfunc(MD5(%lowcase(&packageName.)),hex7.); */
|
||||
data _null_; call symputX("_PackageFileref_", "P" !! put(MD5("%lowcase(&packageName.)"), hex7. -L), "L"); run;
|
||||
|
||||
/* when the packages reference is multi-directory search for the first one containing the package */
|
||||
data _null_;
|
||||
exists = 0;
|
||||
length packages $ 32767 p $ 4096;
|
||||
packages = resolve(symget("path"));
|
||||
if char(packages,1) ^= "(" then packages = quote(strip(packages)); /* for paths with spaces */
|
||||
do i = 1 to kcountw(packages, "()", "QS");
|
||||
p = dequote(kscanx(packages, i, "()", "QS"));
|
||||
exists + fileexist(catx("/", p, "%lowcase(&packageName.).zip"));
|
||||
if exists then leave;
|
||||
end;
|
||||
if exists then call symputx("path", p, "L");
|
||||
run;
|
||||
|
||||
filename &_PackageFileref_.
|
||||
/* put location of package myPackageFile.zip here */
|
||||
"&path./%lowcase(&packageName.).zip"
|
||||
;
|
||||
%if %sysfunc(fexist(&_PackageFileref_.)) %then
|
||||
%do;
|
||||
/* create hash SHA256 id *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
|
||||
%local HASHING_FILE_exist;
|
||||
%let HASHING_FILE_exist = 0;
|
||||
|
||||
%if %sysfunc(exist(sashelp.vfunc, VIEW)) %then
|
||||
%do;
|
||||
data _null_;
|
||||
set sashelp.vfunc(keep=fncname);
|
||||
where fncname = "HASHING_FILE";
|
||||
call symputX('HASHING_FILE_exist', 1, "L");
|
||||
stop;
|
||||
run;
|
||||
%end;
|
||||
|
||||
%if &HASHING_FILE_exist. = 1 %then
|
||||
%do;
|
||||
options notes;
|
||||
filename &_PackageFileref_. list;
|
||||
|
||||
data _null_;
|
||||
length providedHash $ 100;
|
||||
providedHash = strip(symget("hash"));
|
||||
select;
|
||||
when ( 'F*' = upcase(substr(providedHash,1,2)) ) /* F = file digest */
|
||||
SHA256 = 'F*' !! HASHING_FILE("SHA256", pathname("&_PackageFileref_.",'F'), 0);
|
||||
when ( 'C*' = upcase(substr(providedHash,1,2)) ) /* C = content digest */
|
||||
SHA256 = 'C*' !! HASHING_FILE("SHA256", "&_PackageFileref_.", 4);
|
||||
otherwise /* legacy approach, without C or F, digest value equivalent to C */
|
||||
SHA256 = HASHING_FILE("SHA256", "&_PackageFileref_.", 4);
|
||||
end;
|
||||
put "Provided Hash: " providedHash;
|
||||
put "SHA256 digest: " SHA256;
|
||||
put " ";
|
||||
|
||||
if upcase(SHA256) = upcase(providedHash) then
|
||||
do;
|
||||
put "NOTE: Package verification SUCCESSFUL.";
|
||||
put "NOTE- Generated hash is EQUAL to the provided one.";
|
||||
end;
|
||||
else
|
||||
do;
|
||||
put "ERROR: Package verification FAILED!!";
|
||||
put "ERROR- Generated hash is DIFFERENT than the provided one.";
|
||||
put "ERROR- Confirm if the package is genuine.";
|
||||
end;
|
||||
run;
|
||||
%let HASHING_FILE_exist = 0;
|
||||
%end;
|
||||
%else
|
||||
%put WARNING: Verification impossible! Minimum SAS version required for the process is 9.4M6. ;
|
||||
/*-+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-*/
|
||||
%end;
|
||||
%else %put ERROR:[&sysmacroname] File "&path./&packageName..zip" does not exist!;
|
||||
filename &_PackageFileref_. clear;
|
||||
|
||||
options ls = &ls_tmp. ps = &ps_tmp.
|
||||
¬es_tmp. &source_tmp.
|
||||
&stimer_tmp. &fullstimer_tmp.
|
||||
msglevel=&msglevel_tmp.;
|
||||
|
||||
%ENDofverifyPackage:
|
||||
%mend verifyPackage;
|
||||
/**/
|
||||
|
||||
387
SPF/SPFinit.md
387
SPF/SPFinit.md
@@ -8,26 +8,28 @@
|
||||
* [the `listPackages` macro](#listpackages)
|
||||
* [the `verifyPackage` macro](#verifypackage)
|
||||
* [the `previewPackage` macro](#previewPackage)
|
||||
* [the `generatePackage` macro](#generatepackage)
|
||||
* [the `generatePackage` macro](#generatepackage)
|
||||
* [the `extendPackagesFileref` macro](#extendpackagesfileref)
|
||||
* [the `loadPackageAddCnt` macro](#loadpackageaddcnt)
|
||||
* [Some more examples](#some-more-examples)
|
||||
|
||||
---
|
||||
|
||||
|
||||
## This is short SAS PAckages Framework help information <a name="helpinfo"></a>
|
||||
## This is short SAS Packages Framework help information <a name="helpinfo"></a>
|
||||
|
||||
A **SAS package** is an automatically generated, single, stand alone *zip* file containing organised and ordered code structures, created by the developer and extended with additional automatically generated "driving" files (i.e. description, metadata, load, unload, and help files).
|
||||
|
||||
The *purpose of a package* is to be a simple, and easy to access, code sharing medium, which will allow: on the one hand, to separate the code complex dependencies created by the developer from the user experience with the final product and, on the other hand, reduce developer's and user's unnecessary frustration related to a remote deployment process.
|
||||
|
||||
In this repository we are presenting the **SAS Packages Framework** which allows to develop and use SAS packages. The latest version of SPF is **`20201115`**.
|
||||
In this repository we are presenting the **SAS Packages Framework** which allows to develop and use SAS packages. The latest version of SPF is **`20231210`**.
|
||||
|
||||
**To get started with SAS Packages** try this [**`Getting Started with SAS Packages`**](https://github.com/yabwon/SAS_PACKAGES/blob/main/SPF/Documentation/Getting_Started_with_SAS_Packages.pdf "Getting Started with SAS Packages") presentation (see the `./SPF/Documentation` directory).
|
||||
|
||||
**The documentation and more advance reading** would be the [**`SAS(r) packages - the way to share (a how to)- Paper 4725-2020 - extended.pdf`**](https://github.com/yabwon/SAS_PACKAGES/blob/main/SPF/Documentation/SAS(r)%20packages%20-%20the%20way%20to%20share%20(a%20how%20to)-%20Paper%204725-2020%20-%20extended.pdf "SAS packages - the way to share") article (see the `./SPF/Documentation` directory).
|
||||
|
||||
|
||||
*Note:* Filenames references `packages` and `package` are reserved keywords.
|
||||
*Note:* Filenames references `packages` and `package` are **reserved keywords.**
|
||||
The first one should be used to point local folder with packages and the framework.
|
||||
The second is used internally by macros.
|
||||
After assigning the directory do not change them when using the SPF since it may affect stability of the framework.
|
||||
@@ -38,7 +40,7 @@ After assigning the directory do not change them when using the SPF since it may
|
||||
## This is short help information for the `installPackage` macro <a name="installpackage"></a>
|
||||
--------------------------------------------------------------------------------------------
|
||||
|
||||
Macro to install SAS packages, version `20201115`
|
||||
Macro to install SAS packages, version `20231210`
|
||||
|
||||
A SAS package is a zip file containing a group
|
||||
of SAS codes (macros, functions, data steps generating
|
||||
@@ -48,6 +50,9 @@ After assigning the directory do not change them when using the SPF since it may
|
||||
in the packages folder. The process of installation is equivalent with
|
||||
manual downloading the package zip file into the packages folder.
|
||||
|
||||
In case the packages fileref is a multi-directory one the first directory
|
||||
will be selected as a destination.
|
||||
|
||||
--------------------------------------------------------------------------------------------
|
||||
|
||||
### Parameters:
|
||||
@@ -60,13 +65,44 @@ After assigning the directory do not change them when using the SPF since it may
|
||||
If the package name is *SPFinit* or *SASPackagesFramework*
|
||||
then the framework itself is downloaded.
|
||||
|
||||
- `sourcePath=` Location of the package, e.g. "www.some.web.page/" (mind the "/" at the end of the path!) <br>
|
||||
Current default location for packages is: <br> `https://raw.githubusercontent.com/yabwon/SAS_PACKAGES/main/packages/` <br>
|
||||
Current default location for the framework is: <br> `https://raw.githubusercontent.com/yabwon/SAS_PACKAGES/main/SPF/`
|
||||
- `sourcePath=` Location of the package, e.g. "www.some.web.page/" (mind the "/" at the end of the path!)
|
||||
Current default location for packages is:
|
||||
`https://github.com/SASPAC/`
|
||||
Current default location for the framework is:
|
||||
`https://raw.githubusercontent.com/yabwon/SAS_PACKAGES/main/SPF/`
|
||||
|
||||
- `mirror=` Indicates which web location for packages installation is used.
|
||||
Value `0` indicates:
|
||||
`https://github.com/SASPAC/`
|
||||
Value `1` indicates:
|
||||
`https://raw.githubusercontent.com/yabwon/SAS_PACKAGES/main`
|
||||
Value `2` indicates:
|
||||
`https://pages.mini.pw.edu.pl/~jablonskib/SASpublic/SAS_PACKAGES`
|
||||
Default value is `0`.
|
||||
|
||||
- `version=` Indicates which historical version of a package to install.
|
||||
Historical version are available only if `mirror=0` is set.
|
||||
Default value is null which means "install the latest".
|
||||
When there are multiple packages to install version
|
||||
is scan sequentially.
|
||||
|
||||
- `replace=` With default value of `1` it causes existing package file
|
||||
to be replaceed by new downloaded file.
|
||||
to be replaced by new downloaded file.
|
||||
|
||||
- `URLuser=` A user name for the password protected URLs, no quotes needed.
|
||||
|
||||
- `URLpass=` A password for the password protected URLs, no quotes needed.
|
||||
|
||||
- `URLoptions=` Options for the `sourcePath` URLs filename. Consult the SAS
|
||||
documentation for the further details.
|
||||
|
||||
- `loadAddCnt=` *Optional.* A package zip may contain additional
|
||||
content. The option indicates if it should be loaded
|
||||
Default value of zero (`0`) means "No", one (`1`)
|
||||
means "Yes". Content is extracted into the **packages** fileref
|
||||
directory in `<packageName>_AdditionalContent` folder.
|
||||
For other locations use `%loadPackageAddCnt()` macro.
|
||||
|
||||
--------------------------------------------------------------------------------------------
|
||||
|
||||
Visit: `https://github.com/yabwon/SAS_PACKAGES/tree/main/SPF/Documentation` to learn more.
|
||||
@@ -91,11 +127,29 @@ filename packages "C:/SAS_PACKAGES"; %* setup a directory for packages;
|
||||
%unloadPackage(SQLinDS) %* unload the package content from the SAS session;
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
### Example ################################################################################
|
||||
|
||||
Enabling the SAS Package Framework
|
||||
from the local directory and installing & loading
|
||||
the multiple packages from the Internet.
|
||||
|
||||
Assume that the `SPFinit.sas` file
|
||||
is located in the "C:/SAS_PACKAGES/" folder.
|
||||
|
||||
Run the following code in your SAS session:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
filename packages "C:/SAS_PACKAGES";
|
||||
%include packages(SPFinit.sas);
|
||||
|
||||
%installPackage(baseplus(1.17) macroarray(1.0) dfa(0.5) GSM)
|
||||
%loadPackageS(GSM, baseplus(1.17), macroarray(1.0), dfa(0.5))
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
## This is short help information for the `helpPackage` macro <a name="helppackage"></a>
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Macro to get help about SAS packages, version `20201115`
|
||||
Macro to get help about SAS packages, version `20231210`
|
||||
|
||||
A SAS package is a zip file containing a group
|
||||
of SAS codes (macros, functions, data steps generating
|
||||
@@ -136,6 +190,11 @@ filename packages "C:/SAS_PACKAGES"; %* setup a directory for packages;
|
||||
and use helpPackage in the following form:
|
||||
`%helpPackage(PiPackage, , zip=disk, options=)`
|
||||
|
||||
- `packageContentDS=` *Optional.* Indicates if a data set with package
|
||||
content should be generated in `WORK`,
|
||||
with default value (`0`) the dataset is not produced,
|
||||
if set to `1` then `WORK.packageName_content`.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Visit: `https://github.com/yabwon/SAS_PACKAGES/tree/main/SPF/Documentation`
|
||||
@@ -161,11 +220,12 @@ filename packages "C:/SAS_PACKAGES"; %* setup a directory for packages;
|
||||
%unloadPackage(SQLinDS) %* unload the package content from the SAS session;
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
---
|
||||
|
||||
## This is short help information for the `loadPackage` macro <a name="loadpackage"></a>
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Macro to *load* SAS packages, version `20201115`
|
||||
Macro to *load* SAS packages, version `20231210`
|
||||
|
||||
A SAS package is a zip file containing a group
|
||||
of SAS codes (macros, functions, data steps generating
|
||||
@@ -197,24 +257,40 @@ filename packages "C:/SAS_PACKAGES"; %* setup a directory for packages;
|
||||
package is provided in required version,
|
||||
default value: `.`
|
||||
|
||||
- `lazyData=` *Optional.* A list of names of lazy datasets to be
|
||||
loaded. If not null datasets from the list are loaded
|
||||
instead of the package.
|
||||
- `lazyData=` *Optional.* A space separated list of names of lazy
|
||||
datasets to be loaded. If not null datasets from the
|
||||
list are loaded instead of the package.
|
||||
An asterisk (*) means *load all lazy datasets*.
|
||||
|
||||
- `zip=` Standard package is zip (lowcase),
|
||||
- `zip=` *Optional.* Standard package is zip (lowcase),
|
||||
e.g. `%loadPackage(PiPackage)`.
|
||||
If the zip is not available use a folder.
|
||||
Unpack data to "pipackage.disk" folder
|
||||
and use loadPackage in the following form:
|
||||
`%loadPackage(PiPackage, zip=disk, options=)`
|
||||
|
||||
- `cherryPick=` *Optional.* A space separated list of selected elements
|
||||
of the package to be loaded into the SAS session.
|
||||
Default value of an asterisk (*) means:
|
||||
"load all elements of the package".
|
||||
|
||||
- `loadAddCnt=` *Optional.* A package zip may contain additional
|
||||
content. The option indicates if it should be loaded
|
||||
Default value of zero (`0`) means "No", one (`1`)
|
||||
means "Yes". Content is extracted into the **Work**
|
||||
directory in `<packageName>_AdditionalContent` folder.
|
||||
For other locations use `%loadPackageAddCnt()` macro.
|
||||
|
||||
- `suppressExec=` *Optional.* Indicates if loading of `exec` type files
|
||||
should be suppressed, default value is `0`,
|
||||
when set to `1` `exec` files are *not* loaded
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Visit: `https://github.com/yabwon/SAS_PACKAGES/tree/main/SPF/Documentation`
|
||||
to learn more.
|
||||
|
||||
## Example ####################################################################
|
||||
## Example 1 ##################################################################
|
||||
|
||||
Enabling the SAS Package Framework
|
||||
from the local directory and installing & loading
|
||||
@@ -234,11 +310,74 @@ filename packages "C:/SAS_PACKAGES"; %* setup a directory for packages;
|
||||
%unloadPackage(SQLinDS) %* unload the package content from the SAS session;
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
## Example 2 ##################################################################
|
||||
|
||||
Enabling the SAS Package Framework
|
||||
from the local directory and installing & cherry picking
|
||||
elements of the BasePlus package.
|
||||
|
||||
Assume that the `SPFinit.sas` file
|
||||
is located in the "C:/SAS_PACKAGES/" folder.
|
||||
|
||||
Run the following code in your SAS session:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
filename packages "C:/SAS_PACKAGES"; %* setup a directory for packages;
|
||||
%include packages(SPFinit.sas); %* enable the framework;
|
||||
|
||||
%installPackage(BasePlus) %* install the package from the Internet;
|
||||
%loadPackage(BasePlus, cherryPick=getVars) %* cherry pick the content;
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
## Utility macros generated during loading a package ###########################
|
||||
|
||||
If a package contains IML modules or CASL user defined functions additional
|
||||
utility macros for IML Modules and CASL UDFs are generated when package is loaded.
|
||||
|
||||
Macros are generated with the following names: `%<packageName>IML()` and `%<packageName>CASLudf()`.
|
||||
|
||||
Their purpose is to make loading of Modules or UDFs (with potentially multiple
|
||||
dependencies) easy in Proc IML and Proc CAS.
|
||||
|
||||
Run them, accordingly, as the first line in the Proc IML or Proc CAS to access the package content.
|
||||
For Proc IML the use is as follows:
|
||||
~~~~~~sas
|
||||
proc IML;
|
||||
%<packageName>IML()
|
||||
|
||||
<... your code using IML modules from the package ...>
|
||||
quit;
|
||||
~~~~~~
|
||||
For Proc CAS the use is as follows:
|
||||
~~~~~~sas
|
||||
proc CAS;
|
||||
%<packageName>CASLudf()
|
||||
|
||||
<... your code using CASL UDFs from the package ...>
|
||||
quit;
|
||||
~~~~~~
|
||||
|
||||
If a utility macro is generated appropriate note and a code snippet
|
||||
is printed in the log of the package loading process.
|
||||
|
||||
In 99% cases macros are used with default parameters values but,
|
||||
in case when deeper insight about macros parameters is needed,
|
||||
help info is printed in the log when the following code is run:
|
||||
~~~~~~sas
|
||||
%<packageName>IML(list=HELP)
|
||||
~~~~~~
|
||||
or
|
||||
~~~~~~sas
|
||||
%<packageName>CASLudf(list=HELP)
|
||||
~~~~~~
|
||||
|
||||
If created, those macros are automatically deleted when the `%unloadPackage()` macro is run.
|
||||
|
||||
---
|
||||
|
||||
## This is short help information for the `loadPackageS` macro <a name="loadpackages"></a>
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Macro wrapper for the loadPackage macro, version `20201115`
|
||||
Macro wrapper for the loadPackage macro, version `20231210`
|
||||
|
||||
A SAS package is a zip file containing a group
|
||||
of SAS codes (macros, functions, data steps generating
|
||||
@@ -287,7 +426,7 @@ filename packages "C:/SAS_PACKAGES"; %* setup a directory for packages;
|
||||
## This is short help information for the `unloadPackage` macro <a name="unloadpackage"></a>
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Macro to unload SAS packages, version `20201115`
|
||||
Macro to unload SAS packages, version `20231210`
|
||||
|
||||
A SAS package is a zip file containing a group
|
||||
of SAS codes (macros, functions, data steps generating
|
||||
@@ -352,7 +491,7 @@ filename packages "C:/SAS_PACKAGES"; %* setup a directory for packages;
|
||||
## This is short help information for the `listPackages` macro <a name="listpackages"></a>
|
||||
-----------------------------------------------------------------------------------------
|
||||
|
||||
Macro to list available SAS packages, version `20201115`
|
||||
Macro to list available SAS packages, version `20231210`
|
||||
|
||||
A SAS package is a zip file containing a group
|
||||
of SAS codes (macros, functions, data steps generating
|
||||
@@ -393,7 +532,7 @@ filename packages "C:/SAS_PACKAGES"; %* setup a directory for packages;
|
||||
## This is short help information for the `verifyPackage` macro <a name="verifypackage"></a>
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Macro to verify SAS package with it hash digest, version `20201115`
|
||||
Macro to verify SAS package with it hash digest, version `20231210`
|
||||
|
||||
A SAS package is a zip file containing a group
|
||||
of SAS codes (macros, functions, data steps generating
|
||||
@@ -401,6 +540,7 @@ filename packages "C:/SAS_PACKAGES"; %* setup a directory for packages;
|
||||
|
||||
The `%verifyPackage()` macro generate package SHA256 hash
|
||||
and compares it with the one provided by the user.
|
||||
Works with `zip` packages only.
|
||||
|
||||
|
||||
*Minimum SAS version required for the process is 9.4M6.*
|
||||
@@ -439,14 +579,14 @@ filename packages "C:/SAS_PACKAGES"; %* set-up a directory for packages;
|
||||
%include packages(SPFinit.sas); %* enable the framework;
|
||||
|
||||
%installPackage(SQLinDS) %* install the package from the Internet;
|
||||
%verifPackage(SQLinDS, %* verify the package with provided hash;
|
||||
%verifyPackage(SQLinDS, %* verify the package with provided hash;
|
||||
hash=HDA478ANJ3HKHRY327FGE88HF89VH89HFFFV73GCV98RF390VB4)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
## This is short help information for the `previewPackage` macro <a name="previewpackage"></a>
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Macro to get previwe of a SAS packages, version `20201115`
|
||||
Macro to get previwe of a SAS packages, version `20231210`
|
||||
|
||||
A SAS package is a zip file containing a group
|
||||
of SAS codes (macros, functions, data steps generating
|
||||
@@ -507,13 +647,13 @@ filename packages "C:/SAS_PACKAGES"; %* setup a directory for packages;
|
||||
%include packages(SPFinit.sas); %* enable the framework;
|
||||
|
||||
%installPackage(SQLinDS) %* install the package from the Internet;
|
||||
%previewpPackage(SQLinDS) %* get content of the package;
|
||||
%previewPackage(SQLinDS) %* get content of the package;
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
## This is short help information for the `generatePackage` macro <a name="generatepackage"></a>
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Macro to generate SAS packages, version `20201115`
|
||||
Macro to generate SAS packages, version `20231210`
|
||||
|
||||
A SAS package is a zip file containing a group
|
||||
of SAS codes (macros, functions, data steps generating
|
||||
@@ -526,7 +666,7 @@ filename packages "C:/SAS_PACKAGES"; %* setup a directory for packages;
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Visit: `https://github.com/yabwon/SAS_PACKAGES/tree/main/SPF/Documentation`
|
||||
Visit: `https://github.com/yabwon/SAS_PACKAGES/tree/main/SPF/Documentation`
|
||||
to read about the details of package generation process.
|
||||
|
||||
### Parameters:
|
||||
@@ -544,18 +684,37 @@ filename packages "C:/SAS_PACKAGES"; %* setup a directory for packages;
|
||||
|
||||
- `packages=` Location of other packages for testing
|
||||
if there are dependencies in loading the package.
|
||||
Has to be a single directory, if more than one are
|
||||
provided than only the first is used.
|
||||
If path to location contains spaces it should be quoted!
|
||||
|
||||
- `testResults=` Location where tests results should be stored,
|
||||
if null (the default) then the session WORK is used.
|
||||
- `testResults=` Location where tests results should be stored,
|
||||
if null (the default) then the session WORK is used.
|
||||
|
||||
- `sasexe=` Location of a DIRECTORY where the SAS binary is located,
|
||||
if null (the default) then the `!SASROOT` is used.
|
||||
|
||||
- `sascfgFile=` Location of a FILE with testing session configuration
|
||||
parameters, if null (the default) then no config file
|
||||
is pointed during the SAS invocation,
|
||||
if set to `DEF` then the `!SASROOT/sasv9.cfg` is used.
|
||||
|
||||
- `delTestWork=` Indicates if `WORK` directories generated by user tests
|
||||
should be deleted, i.e. the (NO)WORKTERM option is set.
|
||||
The default value: `1` means "delete tests work".
|
||||
Available values are `0` and `1`.
|
||||
|
||||
- `markdownDoc=` Indicates if a markdown file with documentation
|
||||
be generated from help information blocks.
|
||||
The default value: `0` means "do not generate the file".
|
||||
Available values are `0` and `1`.
|
||||
|
||||
- `easyArch=` When creating documentation file (`markdownDoc=1`)
|
||||
indicates if a copy of the zip and markdown files
|
||||
with the version number in the file name be created
|
||||
The default value: `0` means "do not create files".
|
||||
Available values are `0` and `1`.
|
||||
|
||||
- `sasexe=` Location of a DIRECTORY where the SAS binary is located,
|
||||
if null (the default) then the `!SASROOT` is used.
|
||||
|
||||
- `sascfgfile=` Location of a FILE with testing session configuration
|
||||
parameters, if null (the default) then no config file
|
||||
is pointed during the SAS invocation,
|
||||
if set to `DEF` then the `!SASROOT/sasv9.cfg` is used.
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
@@ -572,7 +731,7 @@ The file should contain the following obligatory information:
|
||||
Type: Package
|
||||
Package: PackageName
|
||||
Title: A title/brief info for log note about your package.
|
||||
Version: X.Y
|
||||
Version: X.Y.Z
|
||||
Author: Firstname1 Lastname1 (xxxxxx1@yyyyy.com), Firstname2 Lastname2 (xxxxxx2@yyyyy.com)
|
||||
Maintainer: Firstname Lastname (xxxxxx@yyyyy.com)
|
||||
License: MIT
|
||||
@@ -596,8 +755,13 @@ Name of the `type` of folder and `files.sas` inside must be in the _low_ case le
|
||||
If order of loading is important, the sequential number
|
||||
can be used to order multiple types in the way you wish.
|
||||
|
||||
If folder name starts with `!` (e.g., `!ignore_me`) or *type* of the folder is "unknown" (e.g., not supported one)
|
||||
the content of such folder is ignored during package generation process.
|
||||
|
||||
The "tree structure" of the folder could be for example as follows:
|
||||
|
||||
All files have to have `.sas` extension. Other files are ignored.
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
<packageName>
|
||||
..
|
||||
@@ -626,7 +790,7 @@ The "tree structure" of the folder could be for example as follows:
|
||||
|
|
||||
+-004_format [one file one format,
|
||||
| | option LIB= should be: work.&packageName.format
|
||||
| | (literally with macrovariable name and "format" sufix)]
|
||||
| | (literally with macrovariable name and "format" suffix)]
|
||||
| |
|
||||
| +-efg.sas [a file with a code creating format EFG and informat EFG]
|
||||
|
|
||||
@@ -662,15 +826,34 @@ The "tree structure" of the folder could be for example as follows:
|
||||
| |
|
||||
| +-abc.sas [a file with a code creating IML module ABC, _without_ "Proc IML" header]
|
||||
|
|
||||
+-011_casludf [one file one CAS-L user defined function,
|
||||
| | only plain code of the function, without "Proc CAS" header]
|
||||
| |
|
||||
| +-abc.sas [a file with a code creating CAS-L user defined function ABC, _without_ "Proc CAS" header]
|
||||
|
|
||||
+-012_kmfsnip [one file one KMF-abbreviation snippet,
|
||||
| | code snipped proper tagging]
|
||||
| |
|
||||
| +-abc.sas [a file with a KMF-abbreviation snippet ABC, _with_ proper tagging, snippets names are in low-case]
|
||||
|
|
||||
+-<sequential number>_<type [in lower case]>
|
||||
|
|
||||
+-00n_clean [if you need to clean something up after exec file execution,
|
||||
+-0nn_clean [if you need to clean something up after exec file execution,
|
||||
| | content of the files will be printed to the log before execution]
|
||||
| |
|
||||
| +-<no file, in this case folder may be skipped>
|
||||
|
|
||||
+-...
|
||||
|
|
||||
+-998_addcnt [additional content for the package, can be only one!, content of this
|
||||
| | directory is copied "as is"]
|
||||
| |
|
||||
| +-arbitrary_file1 [an arbitrary file ]
|
||||
| |
|
||||
| +-subdirectory_with_files [an arbitrary directory with some files inside]
|
||||
| |
|
||||
| +-...
|
||||
|
|
||||
+-999_test [tests executed during package generation, XCMD options must be turned-on]
|
||||
| |
|
||||
| +-test1.sas [a file with a code for test1]
|
||||
@@ -682,8 +865,136 @@ The "tree structure" of the folder could be for example as follows:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
--------------------------------------------------------------------------------------------
|
||||
|
||||
## This is short help information for the `extendPackagesFileref` macro <a name="extendpackagesfileref"></a>
|
||||
-----------------------------------------------------------------------------------------
|
||||
|
||||
Macro to list directories pointed by 'packages' fileref, version `20231210`
|
||||
|
||||
A SAS package is a zip file containing a group
|
||||
of SAS codes (macros, functions, data steps generating
|
||||
data, etc.) wrapped up together and embedded inside the zip.
|
||||
|
||||
The `%extendPackagesFileref()` macro lists directories pointed by
|
||||
the packages fileref. It allows to add new dierctories to packages folder list.
|
||||
|
||||
### Parameters:
|
||||
|
||||
1. `packages` *Optional.* A valid fileref name, when empty the "packages" is used
|
||||
When used as: `%extendPackagesFileref(HELP)` it displays this help information.
|
||||
|
||||
------------------------------------------------------------------------------------------
|
||||
|
||||
Visit: `https://github.com/yabwon/SAS_PACKAGES/tree/main/SPF/Documentation`
|
||||
to learn more.
|
||||
|
||||
### Example ###################################################################
|
||||
|
||||
Enabling the SAS Package Framework
|
||||
from the local directory and adding
|
||||
new directory.
|
||||
|
||||
Assume that the `SPFinit.sas` file
|
||||
is located in one of "C:/SAS_PK1" or "C:/SAS_PK2" folders.
|
||||
|
||||
Run the following code in your SAS session:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
filename packages ("C:/SAS_PK1" "C:/SAS_PK2"); %* setup a directory for packages;
|
||||
%include packages(SPFinit.sas); %* enable the framework;
|
||||
|
||||
filename packages ("D:/NEW_DIR" %extendPackagesFileref()); %* add new directory;
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
-----------------------------------------------------------------------------------------
|
||||
|
||||
## This is short help information for the `loadPackageAddCnt` macro <a name="loadpackageaddcnt"></a>
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Macro to load *additional content* for a SAS package, version `20231210`
|
||||
|
||||
A SAS package is a zip file containing a group
|
||||
of SAS codes (macros, functions, data steps generating
|
||||
data, etc.) wrapped up together and included by
|
||||
a single `load.sas` file (also embedded inside the zip).
|
||||
|
||||
The `%loadPackageAddCnt()` macro loads additional content
|
||||
for a package (of course only if one is provided).
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
### Parameters:
|
||||
|
||||
1. `packageName` *Required.* Name of a package, e.g. myPackage,
|
||||
Required and not null, default use case:
|
||||
`%loadPackageAddCnt(myPackage)`.
|
||||
If empty displays this help information.
|
||||
|
||||
- `path=` *Optional.* Location of a package. By default it
|
||||
looks for location of the **packages** fileref, i.e.
|
||||
`%sysfunc(pathname(packages))`
|
||||
|
||||
- `target=` *Optional.* Location where the directory with
|
||||
additional content will be generated,
|
||||
name of the directory created is set to
|
||||
`<packagename>_AdditionalContent`, the default
|
||||
location is `%sysfunc(pathname(WORK))`
|
||||
|
||||
- `source2=` *Optional.* Option to print out details about
|
||||
what is loaded, null by default.
|
||||
|
||||
- `requiredVersion=` *Optional.* Option to test if the loaded
|
||||
package is provided in required version,
|
||||
default value: `.`
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Visit: `https://github.com/yabwon/SAS_PACKAGES/tree/main/SPF/Documentation`
|
||||
to learn more.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
By *default* additional content is not deployed automatically e.g.,
|
||||
from security point of view, or production job doesn't need it to run, etc.
|
||||
But if there is a need for it there are three ways to get it:
|
||||
|
||||
- The first one ("by-the-book"), and also the recommended one. The additional
|
||||
content is extracted during the automatic installation process using the
|
||||
`\%installPackage()` macro. For this to work the `loadAddCnt=` parameter
|
||||
has to be set to `1`. The additional content is extracted to the
|
||||
`<packageName>_AdditionalContent` directory into the same location where
|
||||
the package is installed i.e., inside `packages` fileref location.
|
||||
- The second one ("by-the-work"), when the additional content is extracted
|
||||
during the loading process with the `\%loadPackage()` macro. For this to
|
||||
work also the `loadAddCnt=` parameter has to be set to `1`. The additional
|
||||
content is extracted to the `<packageName>_AdditionalContent` directory
|
||||
inside the `Work` library location.
|
||||
- The third one ("by-the-user"), when the additional content is extracted
|
||||
with dedicated `%loadPackageAddCnt()` macro. By default the additional
|
||||
content is extracted to the `<packageName>_AdditionalContent` directory
|
||||
inside the `Work` library location too, but it can be altered by changing
|
||||
the `target=` parameter, which indicates the location.
|
||||
|
||||
If done "by-the-book", or "by-the-user" with `target=` parameter, the
|
||||
additional content is not automatically deleted when SAS session ends,
|
||||
in this case the "additionals" have to be deleted manually by the User.
|
||||
|
||||
|
||||
### Example 1 ##################################################################
|
||||
|
||||
Enabling the SAS Package Framework
|
||||
from the local directory and installing & loading additional content
|
||||
for the SQLinDS package.
|
||||
|
||||
Assume that the `SPFinit.sas` file
|
||||
is located in the "C:/SAS_PACKAGES/" folder.
|
||||
|
||||
Run the following code in your SAS session:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
filename packages "C:/SAS_PACKAGES"; %* setup a directory for packages;
|
||||
%include packages(SPFinit.sas); %* enable the framework;
|
||||
|
||||
%installPackage(SQLinDS) %* install the package from the Internet;
|
||||
%loadPackageAddCnt(SQLinDS) %* load additional content for the package;
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
## Some more examples <a name="some-more-examples"></a> #############################################################
|
||||
|
||||
|
||||
3646
SPF/SPFinit.sas
3646
SPF/SPFinit.sas
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2019 - 2020 Bartosz Jablonski
|
||||
Copyright (c) 2019 - 2023 Bartosz Jablonski
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -2,12 +2,16 @@
|
||||
To get started with SAS Packages try this [**`Getting Started with SAS Packages`**](https://github.com/yabwon/SAS_PACKAGES/blob/main/SPF/Documentation/Getting_Started_with_SAS_Packages.pdf "Getting Started with SAS Packages") presentation (see the `./SPF/Documentation` directory).
|
||||
|
||||
## Available packages:
|
||||
Currently the following packages are available:
|
||||
For "backward compatibility"/historical point of view the following packages are available under the `./packages` directory.
|
||||
|
||||
Since *September 2022* the default location for packages is **SASPAC - the SAS Packages Archive** located under: [`https://github.com/SASPAC`](https://github.com/SASPAC) where each package is stored as a separate repository with historical versions too.
|
||||
|
||||
Packages:
|
||||
|
||||
---
|
||||
|
||||
- **SQLinDS**\[2.2\], based on Mike Rhoads' article *Use the Full Power of SAS in Your Function-Style Macros*. The package allows to write SQL queries in the data step, e.g.
|
||||
```
|
||||
- **SQLinDS**\[2.3.0\], based on Mike Rhoads' article *Use the Full Power of SAS in Your Function-Style Macros*. The package allows to write SQL queries in the data step, e.g.
|
||||
```sas
|
||||
data class;
|
||||
set %SQL(
|
||||
select age, name, weight, height
|
||||
@@ -18,22 +22,14 @@ data class;
|
||||
WH = weight + height;
|
||||
run;
|
||||
```
|
||||
SHA256 digest for SQLinDS: CE1A266B9030E5E336B45F53DF483F6913FD8AE88A2884CEE88BEEF621FDBD78
|
||||
SHA256 digest for SQLinDS: F*3C010734B76CA7459C4D35087C899121011CD4AA2932B56335FF11A805C8EF8D
|
||||
|
||||
[Documentation for SQLinDS](https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/sqlinds.md "Documentation for SQLinDS")
|
||||
|
||||
---
|
||||
|
||||
- **MacroCore**\[1\], a macro library for SAS application developers. Over 100 macros for Base SAS, metadata, and Viya. Provided by the [SASjs framework](https://sasjs.io "SASjs framework").
|
||||
|
||||
SHA256 digest for MacroCore: A23C29529F3CE7D0C8BEE9545C5D22D5B5594907547374A5135B8E5A48D7687B
|
||||
|
||||
[Documentation for MacroCore](https://core.sasjs.io "Documentation for MacroCore")
|
||||
|
||||
---
|
||||
|
||||
- **DFA** (Dynamic Function Arrays)\[0.2\], contains set of macros and FCMP functions which implement: a dynamically allocated array, a stack, a fifo queue, an ordered stack, and a priority queue, run `%helpPackage(DFA,createDFArray)` to find examples.
|
||||
```
|
||||
- **DFA** (Dynamic Function Arrays)\[0.5.7\], contains set of macros and FCMP functions which implement: a dynamically allocated array, a stack, a fifo queue, an ordered stack, and a priority queue, run `%helpPackage(DFA,createDFArray)` to find examples.
|
||||
```sas
|
||||
%createDFArray(ArrDynamic, resizefactor=17);
|
||||
|
||||
data _null_;
|
||||
@@ -59,12 +55,14 @@ data _null_;
|
||||
end;
|
||||
run;
|
||||
```
|
||||
SHA256 digest for DFA: C795736F55B3C6EFBEF2E82362694EB017D37C54E6AEC3EB0F6F813F69F54B5F
|
||||
SHA256 digest for DFA: F*012375D87F66EB3A7BF5DDD0CC5AEE28851733EE33CC63231DF9045BEB958168
|
||||
|
||||
[Documentation for DFA](https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/dfa.md "Documentation for DFA")
|
||||
|
||||
---
|
||||
|
||||
- **macroArray**\[0.7\], implementation of an array concept in a macro language, e.g.
|
||||
```
|
||||
- **macroArray**\[1.2.6\], implementation of an array concept in a macro language, e.g.
|
||||
```sas
|
||||
%array(ABC[17] (111:127), macarray=Y);
|
||||
|
||||
%macro test();
|
||||
@@ -82,14 +80,14 @@ SHA256 digest for DFA: C795736F55B3C6EFBEF2E82362694EB017D37C54E6AEC3EB0F6F813F6
|
||||
which = 1:H:2
|
||||
);
|
||||
```
|
||||
SHA256 digest for macroArray: 0F1B985E2FC34C91D2A3BD237DC294502A76913B71266D76702A5E77A78C9CA7
|
||||
SHA256 digest for macroArray: F*3F3893F1FCD78719543703E4353F4CC19811D247C016F220FF729B283C1AD790
|
||||
|
||||
[Documentation for macroArray](https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/macroarray.md "Documentation for macroArray")
|
||||
|
||||
---
|
||||
|
||||
- **BasePlus**\[0.9\] adds a bunch of functionalities I am missing in BASE SAS, such as:
|
||||
```
|
||||
- **BasePlus**\[1.36.0\] adds a bunch of functionalities I am missing in BASE SAS, such as:
|
||||
```sas
|
||||
call arrMissToRight(myArray);
|
||||
call arrFillMiss(17, myArray);
|
||||
call arrFill(42, myArray);
|
||||
@@ -101,15 +99,46 @@ string = catXFn("date9.", "#", myArray);
|
||||
format x bool.;
|
||||
|
||||
%put %getVars(sashelp.class, pattern = ght$, sep = +, varRange = _numeric_);
|
||||
|
||||
%rainCloudPlot(sashelp.cars,DriveTrain,Invoice)
|
||||
|
||||
%zipLibrary(sashelp,libOut=work)
|
||||
|
||||
%bpPIPE(ls -la ~/)
|
||||
|
||||
%dirsAndFiles(C:\SAS_WORK\,ODS=work.result)
|
||||
|
||||
%put %repeatTxt(#,15,s=$) HELLO SAS! %repeatTxt(#,15,s=$);
|
||||
|
||||
%put %date() %time() %datetime();
|
||||
|
||||
%put %date(yymmddn10.) %time(time5.) %datetime(e8601dt.);
|
||||
|
||||
%put %monthShift(2023,1,-5);
|
||||
```
|
||||
SHA256 digest for BasePlus: B25A3992B6FCD13528BEE462B3ADD0F5A6D15E607A6DABAA984CA66B0AD69415
|
||||
SHA256 digest for BasePlus: F*B9F1B3243FD3956F0B68652C21EA1EBC19F3EB0931774A57FECE1F02A9448108
|
||||
|
||||
[Documentation for BasePlus](https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/baseplus.md "Documentation for BasePlus")
|
||||
|
||||
---
|
||||
|
||||
- **dynMacroArray**\[0.2\], set of macros (wrappers for a hash table) emulating dynamic array in the data step (macro predecessor of DFA)
|
||||
- **GSM** (Generate Secure Macros)\[0.22.1\], package allows
|
||||
to create secured macros stored in SAS Proc FCMP functions.
|
||||
The dataset with functions can be shared between different operating systems
|
||||
and allows to generate macros on site without showing their code.
|
||||
|
||||
SHA256 digest for dynMacroArray: 5E8CCC88CC048A0B564CEE37C6CF4013857D9CFF3FA1B6B9AD6F719D08B30005
|
||||
[Recording of presentation with "how it works" description (in Polish)](https://www.youtube.com/watch?v=LtaWPe2sgRY&t=1s "YouTube").
|
||||
|
||||
[The WUSS 2023 Conference article describing the idea](https://www.wuss.org/proceedings/2023/WUSS-2023-Paper-189.pdf "Article about the idea GSM")
|
||||
|
||||
SHA256 digest for GSM: F*80197391195C3EC41BD436DF0C8802D3920E4D22B64009A7DE872FBDF8D4B86E
|
||||
|
||||
[Documentation for GSM](https://github.com/yabwon/SAS_PACKAGES/blob/main/packages/gsm.md "Documentation for GSM")
|
||||
|
||||
---
|
||||
|
||||
- **dynMacroArray**\[0.2.7\], set of macros (wrappers for a hash table) emulating dynamic array in the data step (macro predecessor of DFA). Development of this package is currently on hold.
|
||||
|
||||
SHA256 digest for dynMacroArray: F*C1644842102C87522E22513744B249027306A833AF7951E51D1760FF28656C16
|
||||
|
||||
---
|
||||
|
||||
@@ -1,3 +1,260 @@
|
||||
/* 20240112 */
|
||||
BasePlus: F*B9F1B3243FD3956F0B68652C21EA1EBC19F3EB0931774A57FECE1F02A9448108
|
||||
|
||||
/* 20231201 */
|
||||
macroArray: F*3F3893F1FCD78719543703E4353F4CC19811D247C016F220FF729B283C1AD790
|
||||
|
||||
/* 20231129 */
|
||||
macroArray: F*FFF2C3D854F9B5677F561BA2EB6FAA2CCC652D81F6AF9473ADF0A4CE977E43F0
|
||||
|
||||
/* 20231123 */
|
||||
macroArray: F*A0840B92EB9356EDB318DBE9B579A345C85ABF69E8D5F7C73C144C66F2F74FB4
|
||||
|
||||
/* 20231114 */
|
||||
BasePlus: F*BCD89EDF856762EB8E441BC53933774483258453D1F7D74185F8A1861E414B0E
|
||||
|
||||
/* 20231111 */
|
||||
BasePlus: F*D84CE41A550DC2D5C092C70C04A796E8329F34087A603BEF0CD366910C162E80
|
||||
DFA: F*012375D87F66EB3A7BF5DDD0CC5AEE28851733EE33CC63231DF9045BEB958168
|
||||
dynMacroArray: F*C1644842102C87522E22513744B249027306A833AF7951E51D1760FF28656C16
|
||||
GSM: F*80197391195C3EC41BD436DF0C8802D3920E4D22B64009A7DE872FBDF8D4B86E
|
||||
macroArray: F*2A108D121D4DACAA8752E681301371F80F0500B2EE28A9E3B39678415BCBD6B2
|
||||
SQLinDS: F*3C010734B76CA7459C4D35087C899121011CD4AA2932B56335FF11A805C8EF8D
|
||||
|
||||
/* 20231107 */
|
||||
BasePlus: F*6214654B4575DC8E4BA3CF032924862C2F69A03A6384872BAA9F774EDF6A8DDA
|
||||
GSM: F*8D80AEB2DB7A4531BA124240E7A12EBE717293048561A877EB5B6B039BD11D18
|
||||
macroArray: F*8689194590698F9A00B57FB37BE3CA8D7330F16B3E591CEAF49E6BE0B70D61D0
|
||||
|
||||
/* 20231026 */
|
||||
BasePlus: F*3407AD8068C7528E129034144F9A44CFDF14B7DC34334C64C2F1D67351D1E01E
|
||||
|
||||
/* 20231012 */
|
||||
BasePlus: F*7EF23E80A2C03B29402183D97ECFF608B62BEDD9458848709B52DC362E6201B9
|
||||
|
||||
/* 20230921 */
|
||||
macroArray: F*E9C0C58FB36AC40C76A518066B8C6F9942202A9DB2C2D737E95D2BB6E4ECED50
|
||||
|
||||
/* 20230919 */
|
||||
BasePlus: F*B91771D45C781B6806DBB44A3B491A0784D7698B9F3BBBE1A86EE5594834315F
|
||||
|
||||
/* 20230906 */
|
||||
macroArray: F*6A22A01868F4203862B3685F543D723C7DB8E9AB3C1A6357D2BFA030971B0D3C
|
||||
|
||||
/* 20230904 */
|
||||
BasePlus: F*2FE68DD9B3692B9D46EF85B82F63C7E65010BF9E89D670FD1779F4670FA03F31
|
||||
DFA: F*09EA5201360922A91A9EEE72F4567792E9CFDFB591BA33419E2BF2B31D9B7C62
|
||||
dynMacroArray: F*F50BEDB542D96B07C763EAB7549FBC5F08ED389DC2338BFAAEBFBD1FD20E22B6
|
||||
GSM: F*2FECDDB568B38E206CA4ADA6FDEF5209C0A08B99401A1510D777BABF9DA54682
|
||||
macroArray: F*4FAAEE7DF2854EA31933AE017A89C1615C7291A66A07CCE345041EB0D587ED4E
|
||||
SQLinDS: F*42DC179E1D2B946AD519C4EC04A068061B312E021C3F4BC4826D2775E116E1B9
|
||||
|
||||
/* 20230824 */
|
||||
BasePlus: F*9EEE4F4B99EA725B60141645AB6A50BFEBA32CE54848593F8D832D907D63CAD7
|
||||
|
||||
/* 20230727 */
|
||||
GSM: F*56DC0DCCE06B4281BF3FA6FA3875CBA87772BDA7FAB601B06740A7980FFB0E07
|
||||
|
||||
/* 20230602 */
|
||||
BasePlus: F*D6DC5AD1B60A92AD300B639B3C361C1F7846EB01E5AB35BF4FDDA6E783408172
|
||||
|
||||
/* 20230601 */
|
||||
BasePlus: F*B3CACDA32A5E70940E667DCA859483BD76DB082D19BAF326F28A580226DDD962
|
||||
|
||||
/* 20230526 */
|
||||
BasePlus: F*2A4F3953EC56DB914024457F74286D565C23DCF220FF151040BDB704FD8DDB06
|
||||
|
||||
/* 20230520 */
|
||||
BasePlus: F*0CCAA009D64CC20ED315FA123C233E0383967E635EB8708E7A48EEE3767C6BC5
|
||||
|
||||
/* 20230503 */
|
||||
BasePlus: F*B297440903337E1AE6F12A6001B80B8AB743079847D16D63DF1C649AE51AA411
|
||||
|
||||
/* 20230419 */
|
||||
BasePlus: F*625E56B017C4AA8D436959C0A03C8503773A9A3823D43FA9E0326276E52DA6F2
|
||||
|
||||
/* 20230417 */
|
||||
BasePlus: F*F39F38CE80A5D8EED3BC9F2413CD6DEF38E8657E5DCF427CBA8938EB8C4350B6
|
||||
|
||||
/* 20230411 */
|
||||
BasePlus: F*B5BF05531BF78DCEBC436BD93311FED0436D83AA3D106ABFBAD96B04C7D63DF2
|
||||
DFA: F*924711C77E413B8CFC18336DDA2293A9F5294D02E267C1BB7BC876B4AF0AABE4
|
||||
dynMacroArray: F*6E087F38BB39B93CBF983124272812E14693C4EF5EE0A3A218BD2BAA069A74BF
|
||||
GSM: F*91C619E47EFAB44CCEB8B892BA1D7A8F9948590DA1317B8EA330F5D12642CE0E
|
||||
macroArray: F*85E3BE4D163AC5223B6EC9D3C25C46564A656E3830998B4555A963180D767160
|
||||
SQLinDS: F*3BB422E8C94515DEE9E13E674A0D119794F464D9597C28D5D536E71F64EB5298
|
||||
|
||||
/* 20230401 */
|
||||
BasePlus: F*AD0B78F94A6FD1C394999CBBC8DD16017FB06DFC3FA1F51AC17B43AC8F517432
|
||||
|
||||
/* 20230210 */
|
||||
SQLinDS: F*229ACF1A62E5194A25C75D8E554BEF1B7D29227A498ED5862F23892BB0D57644
|
||||
|
||||
/* 20221215 */
|
||||
BasePlus: A6F1977DC4EC22A39DDC7BCE68CF562AF54351A3D385D488EC3067B5A7C0F3CB
|
||||
DFA: 6DEB02BE1C30453FBC688AF1F561709C7D6BF10B3B67988B238853A2A9D53034
|
||||
dynMacroArray: 7800F36877DC0B9A94B1AC8FFDF8B43ADB216F11B5B26343E41165E7F5E32FC0
|
||||
GSM: 83EC349DF97EFA71187536E8CC6CD62215CE675D20DA355E14D4ACE3FBC6D524
|
||||
macroArray: 8584C249C308B5E8B620ED5F695BC58CD426172FB2EACD5FF9C6899F9DE2B470
|
||||
SQLinDS: 42677CEBB0778A6B72DE9C0071B66A345811EE470289E3847D7737F782E709E0
|
||||
|
||||
|
||||
/* 20221125 */
|
||||
BasePlus: D8DBB7CC5952331FA59FEBBBDD15BC543FE3C89A8BA9150FE6AF5E412868EBE7
|
||||
DFA: 7520CF21CBF1FD4AD2BC05C5DD343E508FCEA507575EBC060B4AD322FB80AB04
|
||||
dynMacroArray: 440920272D1838505EA5C033B1C448C612DE2FCCFD57F157BB90ED980E4001CC
|
||||
GSM: 50D8340E080BEA459E68BE315146AD3B809930DB8DC7B23C7A492C3815ACD83F
|
||||
macroArray: 244B88C82AD7E6E93B8B85BC701ECDDB20B68F38B16C500EE9B49E1167ADC298
|
||||
SQLinDS: D5A66E60602270E5FB1E592FA3E0C2F2C640BC077FE799A2223CB9BA275F6F47
|
||||
|
||||
|
||||
/* 20221121 */
|
||||
BasePlus: EBA9EDB3D50D854288970CC0E965DA6AD5B057F6E6433EEBEC4A02B9A25CF6E2
|
||||
DFA: 3F618EDAC8B4F4BE6C19D606E6BCC58121A16BA1383D2EE64C680B4B7FA9C96A
|
||||
dynMacroArray: DD0BF1768DA05EBB5F8C6E7409A0929E28DF11CB499F75B433D9648855AACAE4
|
||||
GSM: E47C94B536B661DEE390F5C3EA1684DD1A246106F4FBBDAFA57F5E34D4BB16D5
|
||||
macroArray: DA57FFE85F49201FD61A53411D19E97FB5A6AC3C34E34FDF4B913545699551FF
|
||||
SQLinDS: 085F0B8BD4A59343E2913FF9635EA6E551ADD54E9678C35F5096D4A0A895B9C5
|
||||
|
||||
/* 20221112 */
|
||||
BasePlus: A80006D3C1409465E49F383D08F2F3AF1E33D6A67D71A8CAF29747ADC917E2E4
|
||||
DFA: 5A6FD2F6E962E6C191346A141FFAF354E35A546CA93146B55D7C6163BFB1BDD6
|
||||
dynMacroArray: C987C08615A53D7BD7AEC3911EADF436C676EAB3E233E7E422E42995B890E169
|
||||
GSM: 5D1925970C9590CD195C15B8641B01D7857E3B2546323DC77D09154BCCA40922
|
||||
macroArray: 371B92A5ABBE82C53F7D63BC5C0D1EBD4695603D3894D8A9A5D5777D1AB59B30
|
||||
SQLinDS: A070214517CC36590083FCF9D5F488AC6E746793E94B9AA55D09A419CF291B5B
|
||||
|
||||
/* 20220830 */
|
||||
BasePlus: 56B260350FEB7D5118F581B9EFD1B9CE1F0298DCB9A4C000A7654E2FF3F0298C
|
||||
DFA: 5BFFCE78439E1CDDCBB15C95CD287AA4195BF64BB17DDB8FE374EC3535B4F491
|
||||
dynMacroArray: D7E0B8F85C05EBF8622204E0D2F3E990D48D0A9B3911051C3AD44DC98954DDCF
|
||||
GSM: 2AEBC150FBA99A4AAB0265A21C57E89200BFD96B633B898F32743D1C8831A159
|
||||
macroArray: ED12BC96F8A4E9E7C4D651EC1E15479DB9B55D98B274B63C507ED842081F7AB7
|
||||
SQLinDS: 96D0EFE02DF1AE0D7D875A10CAF7EF63CDEF85DD0CF9418934BEFAF0C067D453
|
||||
|
||||
/* 20220511 */
|
||||
BasePlus: 619D4B2562F1D9E42C9C5DCB326E8F4D6A020B5D0CEE29A6174F65F8E1B0E7BD
|
||||
|
||||
/* 20220509 */
|
||||
BasePlus: 4CD3926B9842925C86B80B5B47B47BEA1FB9707826B545B9B4D52AE97BC3617E
|
||||
|
||||
/* 20220508 */
|
||||
BasePlus: 0331C673052D5221DA98C5CC93295634D8A0BC62C7D2FEF9D0D85B0B2DEDE4E9
|
||||
|
||||
/* 20220420 */
|
||||
BasePlus: 12A9A2155D9C6F969DF0A66E3A18D0938B8194FA3AA9D70EDDE1CB71DEF9691E
|
||||
DFA: 6B3FB0B06B47A7EF1BB004B483B0F39B8F553F7F16D02A7E24CDE388BBA704EA
|
||||
dynMacroArray: 7DA9BFDED37C18C4FB5BD7579A81A4B2578EEEF1546D1A3AB5C80DE07C88A615
|
||||
GSM: E6E2A6214EE7DC6E06AA76916A68B216DD7665184E63CF2C01F487A038E71B09
|
||||
macroArray: DF63B0E027827A82038F1C8422787A0BC569BA93104BA1778DB6DD088A5D255C
|
||||
SQLinDS: 701B69BE71B99792803BCE7718ED486259310FFB92E6D77ED1BC029D9CC67B60
|
||||
|
||||
/* 20220406 */
|
||||
GSM: BE9508C8E37706B2EB2FBCA68B64F7DCF63C65E8E24775C92E28FE34E547893D
|
||||
|
||||
/* 20220307 */
|
||||
GSM: F63B8C602C1DB02F4107D9AF78182D87CD64AEA6521163067B7EB6D5C1B368AF
|
||||
|
||||
/* 20220307 */
|
||||
GSM: 8D730316043A6523A3AF2AA15D2820BB75A46E06307F2B8916D30AC102AEE31D
|
||||
|
||||
/* 20220217 */
|
||||
macroArray: DAEB87654D99965BF2B7A6AB14626B3E617D0ABF526E77725DF89A1AB4C812C2
|
||||
|
||||
/* 20220113 */
|
||||
BasePlus: A60A300E083628C65DD6899E7EF95588916F8F66B6A25B32B3228987B6F74857
|
||||
DFA: 5F89AC6AE628EB27D87FF6A9D72A515FFA3FF6694D04DE0D9811BFFB81444ABB
|
||||
dynMacroArray: 766DF3F330B87E99FAC32A00A569D9A45DA1157F591DE34DD0892CD864779409
|
||||
GSM: 3B70D8C31F02CB2B6AC47CC1DB3EC9E462796226CBFF519936AF5EEDB0C46B8F
|
||||
macroArray: 833D747526F4CE83FFD73F9EB3A2A9065401B498DFEC79045A28A42E0E57A8CA
|
||||
SQLinDS: DCAB62267B52822F416BA7E6713A696D843E8092A4E3A37DF06CBE1E1D5DAD11
|
||||
|
||||
/* 20220111 */
|
||||
BasePlus: 1B6AA5A38846C30B3DD3E9FED86CB4ECACF25FBAF3011CBE108ED996C3FBB823
|
||||
|
||||
/* 20211228 */
|
||||
macroArray: 95164E71AF0B86AC816F13821F6468F611C6E5BB9036AC10459CDEB10487B08E
|
||||
|
||||
/* 20211123 */
|
||||
BasePlus: 105F0CEB95C49102BDB085DF67C785301F623CB337D466F07B5E051626E4AE61
|
||||
|
||||
/* 20211119 */
|
||||
BasePlus: 55AC07F7322F504EF22C5D00D46587744CD373E70A83932F837EA8C6ECB6D987
|
||||
|
||||
/* 20211114 */
|
||||
BasePlus: 319109732B5CBD99ADDA6D48EA26DA5236622F9C5D332F94EF282F1C9DCE73F9
|
||||
|
||||
/* 20211113 */
|
||||
BasePlus: 4EDB786B9D6F6D6C5741B5CAC1CB169DD10D8196600B2CB385DDE479A54F0FA3
|
||||
|
||||
/* 20211112 */
|
||||
GSM: F6EE77A3C042E1E083E970BE255D126B52A75205DC1FB9A4A7337D0A89EEC7EB
|
||||
|
||||
/* 20211111 */
|
||||
BasePlus: B34E352EC52E05B8BBE1816E6104F47677CBFDEAF7CD71B8BF04FDBFA01B0EF0
|
||||
DFA: C32A81304A411C1EB6BA7B76EDB8D70550F3935F35A1506E2B8019A2036FB5FF
|
||||
dynMacroArray: 9FE227EF3144431B51063D599148BDD8873509D1B32F1AC2979EC566E1BB1487
|
||||
GSM: BEFAA87266D6DBA3D5983117FC36A24DE03A2F93791AC786DCDB37571A4494AC
|
||||
macroArray: 70032D27081A0EE15BC82B8F14D2A61700FA7C1F0D88B4DB516AB433CD06C4D3
|
||||
SQLinDS: F2BE3CC68C9A34DD324FD35C8287A4F89737E2E28E806E0DD7FB0EBF60F7C569
|
||||
|
||||
/* 20211105 */
|
||||
GSM: 3EAF6E93642CCA9B5B592DF9BED4C8B20B60BCD4B0434720D12D26096717C4A9
|
||||
|
||||
/* 20211005 */
|
||||
BasePlus: D01BDFB50EF023EF51806F5F0ED664523C1A6F25AA2778808558C212E6D74725
|
||||
|
||||
/* 20211001 */
|
||||
BasePlus: 5EAEF846754F19759C0492308478417C9667C9651F1EF14F70E4FF8AB4C857F6
|
||||
|
||||
/* 20210908 */
|
||||
GSM: 93D88D4465B68984E938212241DE55C7B12EBC20601538553AC9E1AC0628C006
|
||||
|
||||
/* 20210818 */
|
||||
BasePlus: C9D26CAC2504634EF25F02B5BD04596B2F873E3C25E8CEDDD7F496A78B184E9F
|
||||
|
||||
/* 20210726 */
|
||||
GSM: 2FC239B5A2216D073826125999BFD64FBA32BFEA3EE6EA2B22EC64E8C1B04144
|
||||
|
||||
/* 20210722 */
|
||||
GSM: 311BCF510B7B189AE9A75C56C4D2F99F844114CC5AD32329FAD690BA1F10422A
|
||||
|
||||
/* 20210719 */
|
||||
GSM: 4322D79C382B9D58EF5E51AFD0856331F8B38B1B35AC21295DADFC43F81B2AF8
|
||||
|
||||
/* 20210716 */
|
||||
GSM: 7134C8672023972BA0D5D5CE1E611F0DBB5F60ADAE847BC59C94FF7E2BEC0278
|
||||
|
||||
/* 20210528 */
|
||||
BasePlus: A321A4BC54D444B82575EC5D443553A096557AD69DC171D578A330277E67637A
|
||||
DFA: 22AB51B85E3344B8C0FB7AF164247881B656F5CBA88BBA974AD8BC41ED79327F
|
||||
dynMacroArray: 67956116578E71327748B7EB3DAFF9D872DBC6F6EDD0DC11B7CF2A54FDA71785
|
||||
macroArray: 849629D3AF3FE3AB45D86990E303F1D5E4D5F9F31C8ED6864C95B0DFAADCA445
|
||||
SQLinDS: 1853CD6262CF66582A33C373AA612CA714B61CB88A1C51745E7A57D5A03C39B4
|
||||
|
||||
/* 20210117 */
|
||||
DFA: 179AAB9DF3DE8F049A4EFDF5FB0BE92AE5F7BFA7708D4365F39D4DC71C4F90FE
|
||||
|
||||
/* 20210109 */
|
||||
BasePlus: 28F3DE865C5E3B914FFB7CC2627D8B0975527EEECEE7AFEAD7B335C3FDC1BFD3
|
||||
DFA: E777D4578DFDEB2277D58264BAB5BFDBEAFD4E538D4831CDCBFFB4216D2441C2
|
||||
dynMacroArray: 8B0777EA3CF41968C0B029AA57B1F809D21D1BAB1B88A35B0EA5DB3C6DD9E748
|
||||
macroArray: 42E87B80450B3E1AD462B9B63B41F34C83B7745AA0F98C3CA72AA19F3B1FF10E
|
||||
SQLinDS: 3034A0C8AC43683AD55698861DBBDEBDE6FC8567D59ECF2BB5F3389FE6BC8062
|
||||
|
||||
/* 20201229 */
|
||||
DFA: 5B41657A8A3BEAD185B13D072BC54902AB81FEAD32330DA8ABA90CF777D4D76E
|
||||
|
||||
/* 20201207 */
|
||||
macroArray: AC3AD58AFBBE459616743DC6346330BD8DD33FBA8CDD595423F181B67D0475BC
|
||||
BasePlus: 9EA40F72191D1916189F043315CA519F6E42CEB05C186F7653AE464D21D21CFB
|
||||
|
||||
/* 20201202 */
|
||||
BasePlus: 7933E6BCFDCA7C04EAAC537773574799759007A5D2AED639E86CF4EA631F1351
|
||||
|
||||
/* 20201130 */
|
||||
DFA: 1FC8D030D576C33F1B5DEB27E17534946209BC148D57A1357CA025ED1E69AEB8
|
||||
|
||||
/* 20201115 */
|
||||
BasePlus: B25A3992B6FCD13528BEE462B3ADD0F5A6D15E607A6DABAA984CA66B0AD69415
|
||||
DFA: C795736F55B3C6EFBEF2E82362694EB017D37C54E6AEC3EB0F6F813F69F54B5F
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*** HELP START ***/
|
||||
/*
|
||||
/*** HELP START ***//*
|
||||
|
||||
## >>> library `dsSQL`: <<< <a name="library-dssql"></a> ########################
|
||||
|
||||
The `dsSQL` library stores temporary views
|
||||
@@ -15,8 +15,8 @@ if not possible, then redirects to the `WORK` location, like:
|
||||
LIBNAME dsSQL BASE "%sysfunc(pathname(WORK))";
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
---
|
||||
*/
|
||||
/*** HELP END ***/
|
||||
|
||||
*//*** HELP END ***/
|
||||
|
||||
data _null_;
|
||||
length rc0 $ 32767 rc1 rc2 8;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*** HELP START ***/
|
||||
/*
|
||||
/*** HELP START ***//*
|
||||
|
||||
## >>> `%dsSQL_Inner()` macro: <<< <a name="dssql-inner-macro"></a> #############
|
||||
|
||||
**Internal** macro called by `dsSQL()` function.
|
||||
@@ -9,8 +9,8 @@ which is then stored in the `dsSQL` library.
|
||||
Recommended for *SAS 9.3* and higher.
|
||||
|
||||
---
|
||||
*/
|
||||
/*** HELP END ***/
|
||||
|
||||
*//*** HELP END ***/
|
||||
|
||||
/* inner macro */
|
||||
%MACRO dsSQL_Inner() / secure;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*** HELP START ***/
|
||||
/*
|
||||
/*** HELP START ***//*
|
||||
|
||||
## >>> `%SQL()` macro: <<< <a name="dssql-macro"></a> ###########################
|
||||
|
||||
The **main** macro which allows to use
|
||||
@@ -41,8 +41,8 @@ data dictionary;
|
||||
run;
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
---
|
||||
*/
|
||||
/*** HELP END ***/
|
||||
|
||||
*//*** HELP END ***/
|
||||
|
||||
|
||||
/* Main User macro */
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*** HELP START ***/
|
||||
/*
|
||||
/*** HELP START ***//*
|
||||
|
||||
## >>> `dsSQL()` function: <<< <a name="dssql-function"></a> ####################
|
||||
|
||||
**Internal** function called by the `%SQL()` macro.
|
||||
@@ -20,8 +20,8 @@ dsSQL(unique_index_2, query)
|
||||
2. `query` - *Character*, internal variable, contains query text.
|
||||
|
||||
---
|
||||
*/
|
||||
/*** HELP END ***/
|
||||
|
||||
*//*** HELP END ***/
|
||||
|
||||
proc fcmp
|
||||
/*inlib = work.&packageName.fcmp*/
|
||||
|
||||
4821
packages/baseplus.md
4821
packages/baseplus.md
File diff suppressed because it is too large
Load Diff
Binary file not shown.
BIN
packages/baseplus_RainCloudPlot_Ex0_9.png
Normal file
BIN
packages/baseplus_RainCloudPlot_Ex0_9.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 41 KiB |
BIN
packages/baseplus_RainCloudPlot_Ex1.png
Normal file
BIN
packages/baseplus_RainCloudPlot_Ex1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 36 KiB |
BIN
packages/baseplus_RainCloudPlot_Ex2a.png
Normal file
BIN
packages/baseplus_RainCloudPlot_Ex2a.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 47 KiB |
BIN
packages/baseplus_RainCloudPlot_Ex2b.png
Normal file
BIN
packages/baseplus_RainCloudPlot_Ex2b.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 62 KiB |
BIN
packages/baseplus_RainCloudPlot_Ex3.png
Normal file
BIN
packages/baseplus_RainCloudPlot_Ex3.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 66 KiB |
1597
packages/dfa.md
Normal file
1597
packages/dfa.md
Normal file
File diff suppressed because it is too large
Load Diff
BIN
packages/dfa.zip
BIN
packages/dfa.zip
Binary file not shown.
Binary file not shown.
336
packages/gsm.md
Normal file
336
packages/gsm.md
Normal file
@@ -0,0 +1,336 @@
|
||||
- [The GSM package](#gsm-package)
|
||||
- [Content description](#content-description)
|
||||
* [`%GSM()` macro](#gsm-macro)
|
||||
* [`%GSMpck_makeFCMPcode()` macro](#gsmpck-makefcmpcode-macro)
|
||||
|
||||
* [License](#license)
|
||||
|
||||
---
|
||||
|
||||
|
||||
# The GSM package [ver. 0.22.1] <a name="gsm-package"></a> ###############################################
|
||||
|
||||
The **GSM** (a.k.a. *Generate Secure Macros*) package allows
|
||||
to create secured macros stored in SAS Proc FCMP functions.
|
||||
The dataset with functions can be shared and allows to generate
|
||||
macros without showing their code.
|
||||
|
||||
The GSM package is basically an automated version of the following:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
proc fcmp outlib = work.gsm.secure ENCRYPT;
|
||||
function generateMacro() $;
|
||||
rc = RESOLVE('
|
||||
%macro secretMacro(x) / SECURE;
|
||||
data test;
|
||||
a = "&x.";
|
||||
run;
|
||||
%mend;
|
||||
');
|
||||
return (rc);
|
||||
endsub;
|
||||
run;
|
||||
|
||||
/* share work.gsm dataset */
|
||||
options cmplib = work.gsm;
|
||||
data _null_;
|
||||
rc = generateMacro();
|
||||
put rc=;
|
||||
run;
|
||||
|
||||
/* enjoy */
|
||||
%secretMacro(42)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
See examples for more details.
|
||||
|
||||
[Recording of presentation with "how it works" description (in Polish)](https://www.youtube.com/watch?v=LtaWPe2sgRY&t=1s "YouTube").
|
||||
|
||||
[The WUSS 2023 Conference article describing the idea](https://www.lexjansen.com/wuss/2023/WUSS-2023-Paper-189.pdf "Article about the idea GSM")
|
||||
|
||||
|
||||
*How to use it:*
|
||||
- Copy all files with your secured macros code into a directory.
|
||||
Best approach is to have one file for one macro.
|
||||
- Copy a path to the directory.
|
||||
- Run the following code:
|
||||
```
|
||||
%GSM(<the path to directory>, cmplib=<name of the dataset>)
|
||||
```
|
||||
- Share generated `ZIP` file (unzip and run the code).
|
||||
|
||||
**Limitations:**
|
||||
- Single macro file cannot be longer than 32760 bytes.
|
||||
|
||||
- Multiline text variable. Consider the following code text file:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
%macro~test()/SECURE;~#@
|
||||
data~test;~#@
|
||||
a~=~"abc~#@
|
||||
~#@
|
||||
def";~#@
|
||||
put~a~hex20.;~#@
|
||||
run;~#@
|
||||
%mend~test;~#@
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
where `~` symbols the space character,
|
||||
`#` symbols the carriage return (`0D`),
|
||||
and `@` symbols the line feed (`0A`).
|
||||
The code file is scanned and inserted into
|
||||
the `resolve()` function argument in a "byte by byte"
|
||||
fashion hence also the "end of line" characters are included.
|
||||
As the result value of variable `a` will be:
|
||||
|
||||
`a = "abc~#@~#@def"`.
|
||||
|
||||
If you want to use the `GSM` package avoid
|
||||
such "style" of coding in your macros.
|
||||
|
||||
|
||||
---
|
||||
|
||||
Package contains:
|
||||
1. macro gsm
|
||||
2. macro gsmpck_makefcmpcode
|
||||
|
||||
Required SAS Components:
|
||||
`Base SAS Software`
|
||||
|
||||
Package contains additional content, run: %loadPackageAddCnt(GSM) to load it
|
||||
or look for the gsm_AdditionalContent directory in the Packages fileref
|
||||
localization (only if additional content was deployed during the installation process).
|
||||
|
||||
*SAS package generated by generatePackage, version 20231111*
|
||||
|
||||
The SHA256 hash digest for package GSM:
|
||||
`F*80197391195C3EC41BD436DF0C8802D3920E4D22B64009A7DE872FBDF8D4B86E`
|
||||
|
||||
|
||||
## >>> `%GSM()` macro: <<< <a name="gsm-macro"></a> #######################
|
||||
|
||||
The `%GSM()` macro is the main macro of
|
||||
the **GSM** (a.k.a. *Generate Secure Macros*) package.
|
||||
|
||||
It converts a list of macros provided by the user into
|
||||
a data set of the Proc FCMP functions. The macros are stored
|
||||
in functions are encrypted which allow to share them without
|
||||
showing their code. *Important* thing is that macros provided
|
||||
by the user *has* to be "secure", i.e. the `secure` option has to
|
||||
be added to the macro definition. See the example:
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
%macro secretMacro(x) / SECURE; /* <- the secure option */
|
||||
<... some code ...>
|
||||
%mend secretMacro;
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
As a result a zip file, containing dataset with functions and
|
||||
code to be executed on site, is generated.
|
||||
|
||||
Since encrypted code is stored in a SAS dataset it has
|
||||
no limitation in sharing between operating systems (like catalogs have).
|
||||
|
||||
*Limitation:* Due to the `Resolve()` function limitations
|
||||
a single macro file cannot be longer than 32760 bytes.
|
||||
|
||||
*Notes:*
|
||||
- All macros have to have the `secure` option added, i.e. `%macro aMacroname(...) / SECURE ;`.
|
||||
- During the execution a test macro, named `%GSMpck_dummyMacroForTests()`, is generated.
|
||||
- The `%GSM()` macro calls the `%GSMpck_makeFCMPcode(...)` macro internally.
|
||||
|
||||
### SYNTAX: ###################################################################
|
||||
|
||||
The basic syntax is the following, the `<...>` means optional parameters:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
%GSM(
|
||||
path
|
||||
<,trim=0>
|
||||
<,cmplib=work.generateMacros>
|
||||
<,source2=>
|
||||
<,outpath=>
|
||||
<,encodingRestricted=>
|
||||
<,secret=>
|
||||
<,lineEnd=>
|
||||
<,encrypt=>
|
||||
)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
**Arguments description**:
|
||||
|
||||
1. `path` - *Required*, indicates a directory which contains files with macros.
|
||||
Only files with `sas` extension are used.
|
||||
|
||||
* `cmplib=` - *Optional*, the default value is `work.generateMacros`.
|
||||
Names the dataset which will contain generated functions.
|
||||
|
||||
* `source2=` - *Optional*, the default value is null.
|
||||
Indicate if `%includ`-ed files are printed out.
|
||||
Any value other than null enables printing.
|
||||
|
||||
* `outpath=` - *Optional*, the default value is set the same as the `path`.
|
||||
Points a directory in which a result (a zip file) is generated.
|
||||
|
||||
* `encodingRestricted=` - *Optional*, the default value is `0`.
|
||||
If set to 1 then if User session encoding is different from
|
||||
encoding of the session which generates the dataset then
|
||||
the generateMacros() function will not execute macro code.
|
||||
|
||||
* `secret=` - *Optional*, the default value is null, in such case the
|
||||
secret is generated from the `sha256(datetime(), hex32.)` function
|
||||
and is printed in the log. When not null then should be
|
||||
alphanumerical constant. Non-alphanumerical characters are removed.
|
||||
Required to execute the `resolve()` function.
|
||||
User who do not know the value will not be able
|
||||
to run the `_maxro_XX_()` function.
|
||||
|
||||
* `lineEnd=` - *Optional*, the default value is `0D0A`, indicates which of:
|
||||
line feed, carriage return, or both, or a space be inserted
|
||||
at the end of line in the intermediate code file that is generated.
|
||||
Value has to be hexadecimal code (_NOT_ null),
|
||||
since the value is resolved as `"&lineEnd."x`, so use e.g.
|
||||
`0A` for line feed, `0D` for carriage return,
|
||||
`0D0A` for both, and `20` for space.
|
||||
|
||||
* `encrypt=` - *Optional*, the default value is `ENCRYPT`.
|
||||
Indicate if `FCMP` functions generated by the package
|
||||
are encrypted. Value has to be either empty or `ENCRYPT`,
|
||||
all other are converted to default. The option is
|
||||
dedicated for debugging, keep the default value
|
||||
for production use.
|
||||
|
||||
* `trim=` - *Deprecated*, the default value is `0`.
|
||||
*Kept for backward compatibility.*
|
||||
|
||||
---
|
||||
|
||||
### Example: ###################################################################
|
||||
|
||||
Example 1. Prepare 2 files: `f1.sas` and `f2.sas` and use the `%GSM()` macro.
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
%let path = %sysfunc(pathname(work))/path2files;
|
||||
|
||||
%put &=path.;
|
||||
options dlcreatedir;
|
||||
libname path "&path.";
|
||||
filename path "&path.";
|
||||
|
||||
data _null_;
|
||||
file path(f1.sas);
|
||||
input;
|
||||
put _infile_;
|
||||
cards4;
|
||||
%macro abc(x) / SECURE;
|
||||
data test;
|
||||
do i = 1 to &x.;
|
||||
put i=;
|
||||
end;
|
||||
run;
|
||||
%mend;
|
||||
;;;;
|
||||
run;
|
||||
|
||||
data _null_;
|
||||
file path(f2.sas);
|
||||
input;
|
||||
put _infile_;
|
||||
cards4;
|
||||
%macro xyz(x) / SECURE;
|
||||
%do i = 1 %to &x.;
|
||||
%put &=i;
|
||||
%end;
|
||||
%mend;
|
||||
;;;;
|
||||
run;
|
||||
|
||||
%GSM(&path., cmplib=work.myMacros)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
## >>> `%GSMpck_makeFCMPcode()` macro: <<< <a name="GSMpck-makeFCMPcode-macro"></a> #######################
|
||||
|
||||
The `%GSMpck_makeFCMPcode()` macro is an internal macro of
|
||||
the **GSM** (a.k.a. *Generate Secure Macros*) package.
|
||||
|
||||
It executes a process of converting
|
||||
a macro provided by the user into
|
||||
a Proc FCMP function.
|
||||
|
||||
Since encrypted code is stored in a SAS dataset it has
|
||||
no limitation in sharing between operating systems (like catalogs have).
|
||||
|
||||
*Limitation:* Single macro file cannot be longer than 32760 bytes.
|
||||
|
||||
### SYNTAX: ###################################################################
|
||||
|
||||
The basic syntax is the following, the `<...>` means optional parameters:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
%GSMpck_makeFCMPcode(
|
||||
path
|
||||
,number
|
||||
<,outlib=work.generateMacros.secure>
|
||||
<,source2=>
|
||||
<,fileNameCode=FNC>
|
||||
<,secret=123456789>
|
||||
<,lineEnd=0A>
|
||||
)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
**Arguments description**:
|
||||
|
||||
1. `path` - *Required*, indicates a directory which contains files with macros.
|
||||
Only files with `sas` extension are used.
|
||||
|
||||
2. `number` - *Required*, a sequential number.
|
||||
|
||||
|
||||
* `cmplib=` - *Optional*, the default value is `work.generateMacros`.
|
||||
Names the dataset which will contain generated functions.
|
||||
|
||||
* `source2=` - *Optional*, the default value is null.
|
||||
Indicate if `%includ`-ed files are printed out.
|
||||
Any value other than null enables printing.
|
||||
|
||||
* `fileNameCode=` - *Optional*, the default value is `FNC`.
|
||||
Internal fileref.
|
||||
|
||||
* `secret=` - *Optional*, internal, the default value is `1234567890`.
|
||||
Alphanumerical constant required to execute the `resolve()`
|
||||
function. User who do not know the value will not be able
|
||||
to run the `_maxro_XX_()` function.
|
||||
|
||||
* `lineEnd=` - *Optional*, the default value is `0D0A`, indicates which of:
|
||||
line feed, carriage return, or both, or a space be inserted
|
||||
at the end of line in the intermediate code file that is generated.
|
||||
Value has to be hexadecimal code (_NOT_ null),
|
||||
since the value is resolved as `"&lineEnd."x`, so use e.g.
|
||||
`0A` for line feed, `0D` for carriage return,
|
||||
`0D0A` for both, and `20` for space.
|
||||
|
||||
* `trim=` - *Deprecated*, the default value is `0`.
|
||||
*Kept for backward compatibility.*
|
||||
|
||||
---
|
||||
|
||||
|
||||
## License ####################################################################
|
||||
|
||||
Copyright (c) Bartosz Jablonski, since 2021
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
---
|
||||
BIN
packages/gsm.zip
Normal file
BIN
packages/gsm.zip
Normal file
Binary file not shown.
@@ -10,13 +10,18 @@
|
||||
* [`%do_over3()` macro](#do-over3-macro)
|
||||
* [`%make_do_over()` macro](#make-do-over-macro)
|
||||
* [`%mcHashTable()` macro](#mchashtable-macro)
|
||||
* [`%mcDictionary()` macro](#mcdictionary-macro)
|
||||
* [`%QzipArrays()` macro](#qziparrays-macro)
|
||||
* [`%zipArrays()` macro](#ziparrays-macro)
|
||||
* [`%sortMacroArray()` macro](#sortmacroarray-macro)
|
||||
|
||||
* [License](#license)
|
||||
|
||||
---
|
||||
|
||||
# The macroArray package [ver. 0.7] <a name="macroarray-package"></a> ###############################################
|
||||
# The macroArray package [ver. 1.2.6] <a name="macroarray-package"></a> ###############################################
|
||||
|
||||
The **macroArray** package implements a macro array facility:
|
||||
The **macroArray** package implements a macroarray facility:
|
||||
- `%array()`,
|
||||
- `%do_over()`,
|
||||
- `%make_do_over()`,
|
||||
@@ -24,6 +29,9 @@ The **macroArray** package implements a macro array facility:
|
||||
- `%concatarrays()`,
|
||||
- `%appendcell()`,
|
||||
- `%mcHashTable()`,
|
||||
- `%zipArrays()`,
|
||||
- `%sortMacroArray()`,
|
||||
- `%mcDictionary()`,
|
||||
- etc.
|
||||
|
||||
The set of macros, which emulates classic
|
||||
@@ -58,15 +66,19 @@ Package contains:
|
||||
7. macro do_over2
|
||||
8. macro do_over3
|
||||
9. macro make_do_over
|
||||
10. macro mchashtable
|
||||
10. macro mcdictionary
|
||||
11. macro mchashtable
|
||||
12. macro qziparrays
|
||||
13. macro sortmacroarray
|
||||
14. macro ziparrays
|
||||
|
||||
Required SAS Components:
|
||||
*Base SAS Software*
|
||||
|
||||
*SAS package generated by generatePackage, version 20201115.*
|
||||
*SAS package generated by generatePackage, version 20231123*
|
||||
|
||||
The SHA256 hash digest for package macroArray:
|
||||
`0F1B985E2FC34C91D2A3BD237DC294502A76913B71266D76702A5E77A78C9CA7`
|
||||
`F*3F3893F1FCD78719543703E4353F4CC19811D247C016F220FF729B283C1AD790`
|
||||
|
||||
---
|
||||
# Content description ############################################################################################
|
||||
@@ -232,7 +244,7 @@ The code of a macro was inspired by
|
||||
|
||||
The `%array()` macro version provided in the package
|
||||
is designed to facilitate
|
||||
the idea of macro array concept, i.e. *a list of
|
||||
the idea of macroarray concept, i.e. *a list of
|
||||
macrovariables with common prefix and numerical suffixes*.
|
||||
Usually such construction is then resolved by
|
||||
double ampersand syntax, e.g. `&&perfix&i` or similar one.
|
||||
@@ -241,7 +253,7 @@ What is new/extension to the `%array()` macro concept are:
|
||||
|
||||
0. The syntax is closer to the data step one.
|
||||
1. It is a pure macro code (it can be executed in any place
|
||||
of 4GL code), this includes generating macro arrays out
|
||||
of 4GL code), this includes generating macroarrays out
|
||||
of datasets.
|
||||
2. When a macroarrray is created it allows also to generate
|
||||
a new macro (named the same as the array name) and replace
|
||||
@@ -266,6 +278,7 @@ The basic syntax is the following, the `<...>` means optional parameters:
|
||||
<,macarray=N>
|
||||
<,ds=>
|
||||
<,vars=>
|
||||
<,q=>
|
||||
)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -300,8 +313,8 @@ The basic syntax is the following, the `<...>` means optional parameters:
|
||||
`%array(myArr[*] x1-x3 (4:6), vnames=Y)`
|
||||
will use `x1`, `x2`, and `x3` as values instead `4`, `5`, and `6`.
|
||||
|
||||
* `macarray=N` - *Optional*, default value `N`, if set to `Y`/`YES` then macro named with array
|
||||
name is compiled to create convenient envelope for multiple ampersands, e.g.
|
||||
* `macarray=N` - *Optional*, default value `N`, if set to `Y`/`YES` then a macro, named with the array
|
||||
name, is compiled to create convenient envelope for multiple ampersands, e.g.
|
||||
`%array(myArr[*] x1-x3 (4:6), macarray=Y)`
|
||||
will create `%myArr(J)` macro which will allow to extract "data"
|
||||
from macroarray like:
|
||||
@@ -313,8 +326,8 @@ The basic syntax is the following, the `<...>` means optional parameters:
|
||||
macrovariables with prefix like the array name and numeric suffixes,
|
||||
then the minimum and the maximum index is determined
|
||||
and all not existing global macrovariables are created and
|
||||
a macro is generated in the same way as for the `Y` value
|
||||
|
||||
a macro is generated in the same way as for the `Y` value.
|
||||
|
||||
* `ds=` - *Optional*, use a dataset as a basis for a macroarray data,
|
||||
if used by default overwrites use of the `array` parameter, honors `macarray=`
|
||||
argument, dataset options are allowed, e.g. `sashelp.class(obs=5)`
|
||||
@@ -331,23 +344,28 @@ The basic syntax is the following, the `<...>` means optional parameters:
|
||||
2) macroarray "WEIGHT" with ALL(no separator is equivalent to #)
|
||||
values of variable "weight" <br>
|
||||
3) macroarray "W" with UNIQUE(|) values of variable "weight" and <br>
|
||||
4) macroarray "AGE" with UNIQUE(|) values of variable "age",
|
||||
|
||||
4) macroarray "AGE" with UNIQUE(|) values of variable "age".
|
||||
|
||||
* `q=` - *Optional*, indicates (when set to `1` or '2') if the value should be surrounded by quotes.
|
||||
It uses `quote(cats(...))` combo under the hood. Default value is `0`.
|
||||
Value `1` is for apostrophes, value `2` is for double quotes.
|
||||
Ignored for `macarray=M`.
|
||||
|
||||
|
||||
---
|
||||
|
||||
### EXAMPLES AND USECASES: ####################################################
|
||||
|
||||
|
||||
**EXAMPLE 1.** Basic use-case.
|
||||
Creating macroarray like in the array statement;
|
||||
values are used by default;
|
||||
different types of brackets are allowed;
|
||||
Creating macroarray like in the array statement.
|
||||
Values not variables names are used by default.
|
||||
Different types of brackets are allowed.
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
%array(a[*] x1-x5 (1:5))
|
||||
|
||||
%array(b{5} (5*17))
|
||||
%array(b{5} (5*17), q=1)
|
||||
|
||||
%* Mind the $ since it is a character array!;
|
||||
%array(c(3) $ 10 ("a A" "b,B" "c;C"))
|
||||
@@ -393,7 +411,7 @@ The basic syntax is the following, the `<...>` means optional parameters:
|
||||
%put &=g0. &=g1. &=g2.;
|
||||
|
||||
%* Or something more complex;
|
||||
%array(gg[0:11] $ 11, function = put(intnx("MONTH", '1jun2018'd, _I_, "E"), yymmn.))
|
||||
%array(gg[0:11] $ 11, function = put(intnx("MONTH", '1jun2018'd, _I_, "E"), yymmn.), q=1)
|
||||
%put &=ggLBOUND. &=ggHBOUND. &=ggN.;
|
||||
%put &=gg0 &=gg1 &=gg2 ... &=gg11;
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -421,10 +439,10 @@ The basic syntax is the following, the `<...>` means optional parameters:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
**EXAMPLE 6a.** "Uppercas Letters"
|
||||
**EXAMPLE 6a.** Quoted "Uppercas Letters"
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
%array(UL[26] $, function = byte(rank("A")+_I_-1) )
|
||||
%array(UL[26] $, function = byte(rank("A")+_I_-1) , q=1)
|
||||
%put &=UL1 &=UL2 ... &=UL25 &=UL26;
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -439,7 +457,7 @@ The basic syntax is the following, the `<...>` means optional parameters:
|
||||
|
||||
%* The range handling, warning;
|
||||
%put *%ll(265)*;
|
||||
|
||||
|
||||
%* The input mode;
|
||||
%put *before:*%ll(2)*;
|
||||
%let %ll(2,I) = bbbbb;
|
||||
@@ -564,10 +582,10 @@ The basic syntax is the following, the `<...>` means optional parameters:
|
||||
Currently the only separator in VARS is a space.
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
%array(ds = sashelp.class, vars = height#h weight weight|w age|)
|
||||
%array(ds = sashelp.class, vars = height#h weight weight|w age|, q=1)
|
||||
%put _user_;
|
||||
|
||||
%array(ds = sashelp.class, vars = height#hght weight weight|wght age|, macarray=Y)
|
||||
%array(ds = sashelp.class, vars = height#hght weight weight|wght age|, macarray=Y, q=1)
|
||||
%put *%hght(&hghtLBOUND.)**%weight(2)**%wght(&wghtHBOUND.)**%age(3)*;
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -587,7 +605,7 @@ The basic syntax is the following, the `<...>` means optional parameters:
|
||||
%let myTest6 = 16;
|
||||
%let myTest9 = 19;
|
||||
|
||||
%array(myTest, macarray=M)
|
||||
%array(myTest, macarray=M, q=1)
|
||||
%do_over(myTest, phrase = %nrstr(%put *&_I_.*%myTest(&_I_.)*;))
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -1193,7 +1211,7 @@ The basic syntax is the following, the `<...>` means optional parameters:
|
||||
1. `H` - *Required*, a hash table macro name and a declaration/definition,
|
||||
e.g. `mcHashTable(HT)`. It names a macro which is generated by
|
||||
the `%mcHashTable()` macro. Provided name cannot be empty
|
||||
or an underscore (`_`). No longer than *16* characters.
|
||||
or an underscore (`_`). No longer than *10* characters.
|
||||
|
||||
2. `METHOD` - *Optional*, if empty (or DECLARE or DCL) then the code of
|
||||
a macro hash table is compiled.
|
||||
@@ -1201,7 +1219,7 @@ The basic syntax is the following, the `<...>` means optional parameters:
|
||||
macrovariables named like "`&H._`" are deleted.
|
||||
|
||||
* `HASH=` - *Optional*, indicates which hashing algorithms should be used,
|
||||
available values are `CRC32` or `MD5`, the `CRC32` is the default.
|
||||
available values are `CRC32` or `MD5`, the `CRC32` is the default.
|
||||
|
||||
---
|
||||
|
||||
@@ -1382,7 +1400,7 @@ See examples below to see use cases.
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
**EXAMPLE 2.** Populate macro hash table from a dataset.
|
||||
**EXAMPLE 3.** Populate macro hash table from a dataset.
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
%mcHashTable(CLASS)
|
||||
@@ -1410,7 +1428,7 @@ run;
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
**EXAMPLE 3.** Data portion may require quoting and un-quoting..
|
||||
**EXAMPLE 4.** Data portion may require quoting and un-quoting..
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
%mcHashTable(CODE)
|
||||
@@ -1427,7 +1445,7 @@ run;
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
**EXAMPLE 4.** Longer lists.
|
||||
**EXAMPLE 5.** Longer lists.
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
%let size = 1000;
|
||||
@@ -1500,7 +1518,7 @@ run;
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
**EXAMPLE 5.** Forbidden names.
|
||||
**EXAMPLE 6.** Forbidden names.
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
%mcHashTable()
|
||||
@@ -1510,7 +1528,7 @@ run;
|
||||
%mcHashTable(ABCDEFGHIJKLMNOP) %* good;
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
**EXAMPLE 5.** Hashing algorithms.
|
||||
**EXAMPLE 7.** Hashing algorithms.
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
%mcHashTable(H1,DCL,HASH=MD5)
|
||||
@@ -1519,6 +1537,730 @@ run;
|
||||
|
||||
---
|
||||
|
||||
## >>> `%mcDictionary()` macro: <<< <a name="mcdictionary-macro"></a> #######################
|
||||
|
||||
The `%mcDictionary()` macro provided in the package
|
||||
is designed to facilitate the idea of a "macro dictionary"
|
||||
concept, i.e. *a list of macrovariables with common prefix
|
||||
and suffixes generated as a hash digest* which allows
|
||||
to use values other than integers as indexes.
|
||||
|
||||
The `%mcDictionary()` macro allows to generate other macros
|
||||
which behaves like a dictionary. See examples below.
|
||||
|
||||
The `%mcDictionary()` macro executes like a pure macro code.
|
||||
|
||||
### SYNTAX: ###################################################################
|
||||
|
||||
The basic syntax is the following, the `<...>` means optional parameters:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
%mcDictionary(
|
||||
H
|
||||
<,METHOD>
|
||||
<,DS=>
|
||||
<,K=Key>
|
||||
<,D=Data>
|
||||
)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
**Arguments description**:
|
||||
|
||||
1. `H` - *Required*, a dictionary macro name and a declaration/definition,
|
||||
e.g. `mcDictionary(HT)`. It names a macro which is generated by
|
||||
the `%mcDictionary()` macro. Provided name cannot be empty
|
||||
or an underscore (`_`). No longer than *13* characters.
|
||||
|
||||
2. `METHOD` - *Optional*, if empty (or DECLARE or DCL) then the code of
|
||||
a macro dictionary is compiled.
|
||||
If `DELETE` then the macro dictionary named by `H` and all
|
||||
macrovariables named like "`&H._`" are deleted.
|
||||
|
||||
* `DS=` - *Optional*, if NOT empty then the `&DS.` dataset is used to
|
||||
populate dictionary with keys from variable `&K.` and data
|
||||
from variable `&D.` Works only during declaration.
|
||||
|
||||
* `K=` - *Optional*, if the `&DS.` is NOT empty then `&K.` holds a name of
|
||||
a variable which keeps or an expression which generates keys values.
|
||||
Default is `Key`.
|
||||
|
||||
* `D=` - *Optional*, if the `&DS.` is NOT empty then `&D.` holds a name of
|
||||
a variable which keeps or an expression which generates data values.
|
||||
Default is `Data`.
|
||||
|
||||
---
|
||||
|
||||
### THE CREATED MACRO `%&H.()`: ####################################################
|
||||
|
||||
The created macro imitates behaviour of a dictionary.
|
||||
|
||||
The basic syntax is the following, the `<...>` means optional parameters:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
%&H.(
|
||||
METHOD
|
||||
<,KEY=>
|
||||
<,DATA=>
|
||||
)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
**Arguments description**:
|
||||
|
||||
1. `METHOD` - *Required*, indicate what behaviour should be executed.
|
||||
Allowed values are:
|
||||
- `ADD`, adds key and data portion to the macro dictionary,
|
||||
*multiple data portions* are NOT available for one key.
|
||||
- `FIND`, tests if given key exists in the macro dictionary
|
||||
and, if yes, returns data value associated with the key.
|
||||
For multiple data portions see the `data=` parameter.
|
||||
- `CHECK`, returns indicator if the key exists in dictionary.
|
||||
- `DEL`, removes key and data portion from the macro dictionary.
|
||||
- `LIST`, prints out a dictionary to the log.
|
||||
- `CLEAR` removes all data and keys values.
|
||||
|
||||
* `KEY=` - *Optional*, provides key value for `ADD`, `FIND`, `CHECK`
|
||||
and `DEL` methods.
|
||||
Leading and trimming spaces are removed from the value.
|
||||
The `MD5(...)` function is used to generate the hash.
|
||||
Default value is `_`.
|
||||
|
||||
* `DATA=` - *Optional*, provides data value for the `ADD` method.
|
||||
Default value is blank.
|
||||
|
||||
|
||||
When macro is executed and when data are added the following types of
|
||||
*global* macrovariables are created:
|
||||
- `&H._########_K`,
|
||||
- `&H._########_V`,
|
||||
- `&H._KEYSNUM`.
|
||||
|
||||
The `#` represents value generated by the `MD5(...)` function for the given key.
|
||||
|
||||
The first type keeps information about the key.
|
||||
|
||||
The second type keeps information about the value of a given key
|
||||
|
||||
The third type keeps the number of unique values of the key.
|
||||
|
||||
See examples below to see use cases.
|
||||
|
||||
---
|
||||
|
||||
### EXAMPLES AND USECASES: ####################################################
|
||||
|
||||
|
||||
**EXAMPLE 1.** Basic use-case.
|
||||
Creating macro dictionary, macro `Dict` is generated.
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
%mcDictionary(Dict)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Add elements to the `Dict`.
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
%Dict(ADD,key=x,data=17)
|
||||
%Dict(ADD,key=y y,data=42)
|
||||
%Dict(ADD,key=z z z,data=303)
|
||||
|
||||
%put _user_;
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Add some duplicates for the key x.
|
||||
See macrovariables created.
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
%Dict(ADD,key=x,data=18)
|
||||
|
||||
%put _user_;
|
||||
|
||||
%Dict(ADD,key=x,data=19)
|
||||
|
||||
%put _user_;
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Check for the key `x` and non existing key `t`.
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
%put ##%Dict(CHECK,key=x)##;
|
||||
%put ##%Dict(CHECK,key=t)##;
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Prints data values for various keys.
|
||||
Key `t` does not exist in the macrodictionary.
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
%put #%Dict(FIND,key=x)#;
|
||||
%put #%Dict(FIND,key=y y)#;
|
||||
%put #%Dict(FIND,key=z z z)#;
|
||||
%put #%Dict(FIND,key=t)#;
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
List dictionary content to the log.
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
%Dict(LIST);
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Delete keys.
|
||||
Key `t` does not exist in the macrodictionary.
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
%put #%Dict(DEL,key=z z z)#;
|
||||
%put _user_;
|
||||
%put #%Dict(DEL,key=t)#;
|
||||
%put _user_;
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Clear and delete macro dictionary `Dict`.
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
%Dict(CLEAR)
|
||||
%put _user_;
|
||||
|
||||
%mcDictionary(Dict,DELETE)
|
||||
%put _user_;
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
**EXAMPLE 2A.** Populate macro dictionary from a dataset "by hand".
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
%mcDictionary(CLASS)
|
||||
%let t = %sysfunc(datetime());
|
||||
data _null_;
|
||||
set sashelp.class;
|
||||
call execute('%CLASS(ADD,key=' !! name !! ',data=' !! age !! ')');
|
||||
run;
|
||||
%put t = %sysevalf(%sysfunc(datetime()) - &t.);
|
||||
%put &=Class_KEYSNUM.;
|
||||
%put _user_;
|
||||
%CLASS(CLEAR)
|
||||
|
||||
|
||||
%mcDictionary(CARS)
|
||||
%let t = %sysfunc(datetime());
|
||||
data _null_;
|
||||
set sashelp.cars(obs=42);
|
||||
call execute('%CARS(ADD,key=' !! catx("|",make,model,type) !! ',data=' !! put(MPG_CITY*10,dollar10.2) !! ')');
|
||||
run;
|
||||
%put t = %sysevalf(%sysfunc(datetime()) - &t.);
|
||||
%put &=CARS_KEYSNUM.;
|
||||
%CARS(LIST);
|
||||
|
||||
%put %CARS(F,key=Audi|TT 3.2 coupe 2dr (convertible)|Sports);
|
||||
|
||||
%CARS(CLEAR)
|
||||
%put &=CARS_KEYSNUM.;
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
**EXAMPLE 2B.** Populate macro dictionary from a dataset "automatically".
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
%let t = %sysfunc(datetime());
|
||||
%mcDictionary(CLASS,DCL,DS=sashelp.class,k=name,d=_N_)
|
||||
%put t = %sysevalf(%sysfunc(datetime()) - &t.);
|
||||
%put &=CLASS_KEYSNUM.;
|
||||
%put _user_;
|
||||
%CLASS(CLEAR)
|
||||
|
||||
|
||||
%let t = %sysfunc(datetime());
|
||||
%mcDictionary(CARS,DCL,DS=sashelp.cars(obs=42),k=catx("|",make,model,type),d=put(MPG_CITY*10,dollar10.2))
|
||||
%put t = %sysevalf(%sysfunc(datetime()) - &t.);
|
||||
%put &=CARS_KEYSNUM.;
|
||||
%CARS(LIST);
|
||||
|
||||
%put %CARS(F,key=Audi|TT 3.2 coupe 2dr (convertible)|Sports);
|
||||
|
||||
%CARS(CLEAR)
|
||||
%put &=CARS_KEYSNUM.;
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
**EXAMPLE 3.** Data portion may require quoting and un-quoting.
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
%mcDictionary(CODE)
|
||||
%CODE(CLEAR)
|
||||
%CODE(ADD,key=data, data=%str(data test; x = 42; run;))
|
||||
%CODE(ADD,key=proc, data=%str(proc print; run;))
|
||||
%CODE(ADD,key=macro,data=%nrstr(%put *1*2*3*4*;))
|
||||
|
||||
%CODE(FIND,key=data)
|
||||
%CODE(FIND,key=proc)
|
||||
%unquote(%CODE(FIND,key=macro))
|
||||
|
||||
%CODE(LIST);
|
||||
|
||||
%mcDictionary(CODE,DELETE)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
**EXAMPLE 4.** Longer lists.
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
%let size = 1000;
|
||||
|
||||
%mcDictionary(AAA)
|
||||
|
||||
%let t = %sysfunc(datetime());
|
||||
data _null_;
|
||||
do i = 1 to &size.;
|
||||
call execute(cats('%AAA(ADD,key=A', i, ',data=', i, ')'));
|
||||
end;
|
||||
run;
|
||||
%put t = %sysevalf(%sysfunc(datetime()) - &t.);
|
||||
%put %AAA(F,key=A555) %AAA(CHECK,key=A555);
|
||||
%put &=AAA_KEYSNUM;
|
||||
%AAA(CLEAR)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
**EXAMPLE 5.** Forbidden names.
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
%mcDictionary()
|
||||
%mcDictionary(_)
|
||||
|
||||
%mcDictionary(ABCDEFGHIJKLMNOPQ) %* bad;
|
||||
%mcDictionary(ABCDEFGHIJKLMNOP) %* good;
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
**EXAMPLE 6.** More fun with datasets.
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
|
||||
data work.metadata;
|
||||
input key :$16. data :$128.;
|
||||
cards;
|
||||
ID ABC-123-XYZ
|
||||
path /path/to/study/data
|
||||
cutoffDT 2023-01-01
|
||||
startDT 2020-01-01
|
||||
endDT 2024-12-31
|
||||
MedDRA v26.0
|
||||
;
|
||||
run;
|
||||
proc print;
|
||||
run;
|
||||
|
||||
%mcDictionary(Study,dcl,DS=work.metadata)
|
||||
|
||||
%put _user_;
|
||||
|
||||
%put *%Study(F,key=ID)**%Study(C,key=ID)*;
|
||||
|
||||
title1 "Study %Study(F,key=ID) is located at %Study(F,key=path)";
|
||||
title2 "it starts %Study(F,key=startDT) and ends %Study(F,key=endDT)";
|
||||
footnote "MedDRA version: %Study(F,key=MedDRA)";
|
||||
|
||||
proc print data=sashelp.class(obs=7);
|
||||
run;
|
||||
|
||||
title;
|
||||
footnote;
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
---
|
||||
|
||||
## >>> `%QzipArrays()` macro: <<< <a name="qziparrays-macro"></a> #######################
|
||||
|
||||
The zipArrays() and QzipArrays() macros
|
||||
allow to use a function on elements of pair of
|
||||
macroarrays.
|
||||
|
||||
For two macroarrays the corresponding
|
||||
elements are taken and the macro applies a function, provided by user,
|
||||
to calculate result of the function on taken elements.
|
||||
|
||||
When one of the arrays is shorter then elements are, by default,
|
||||
"reused" starting from the beginning. But this behaviour can be altered.
|
||||
See examples for the details.
|
||||
|
||||
By default newly created macroarray name is concatenation
|
||||
of first 13 characters of names of arrays used to create the new one,
|
||||
e.g. if arrays names are `abc` and `def` then the result name is `abcdef`,
|
||||
if arrays names are `abcd1234567890` and `efgh1234567890` then the result
|
||||
name is `abcd123456789efgh123456789`
|
||||
|
||||
The `zipArrays()` returns unquoted value [by `%unquote()`].
|
||||
The `QzipArrays()` returns quoted value [by `%superq()`].
|
||||
|
||||
See examples below for the details.
|
||||
|
||||
The `%QzipArrays()` macro executes like a pure macro code.
|
||||
|
||||
### SYNTAX: ###################################################################
|
||||
|
||||
The basic syntax is the following, the `<...>` means optional parameters:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
%QzipArrays(
|
||||
first
|
||||
,second
|
||||
<,function=>
|
||||
<,operator=>
|
||||
<,argBf=>
|
||||
<,argMd=>
|
||||
<,argAf=>
|
||||
<,format=>
|
||||
<,result=>
|
||||
<,macarray=>
|
||||
<,reuse=>
|
||||
)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
**Arguments description**:
|
||||
|
||||
1. `first` - *Required*, a space separated list of texts.
|
||||
|
||||
2. `second` - *Required*, a space separated list of texts.
|
||||
|
||||
* `function = cat` - *Optional*, default value is `cat`,
|
||||
a function which will be applied
|
||||
to corresponding pairs of elements of
|
||||
the first and the second list.
|
||||
|
||||
* `operator =` - *Optional*, default value is empty,
|
||||
arithmetic infix operator used with elements
|
||||
the first and the second list. The first
|
||||
list is used on the left side of the operator
|
||||
the second list is used on the right side
|
||||
of the operator.
|
||||
|
||||
* `argBf =` - *Optional*, default value is empty,
|
||||
arguments of the function inserted
|
||||
*before* elements the first list.
|
||||
If multiple should be comma separated.
|
||||
|
||||
* `argMd =` - *Optional*, default value is empty,
|
||||
arguments of the function inserted
|
||||
*between* elements the first list and
|
||||
the second list.
|
||||
If multiple should be comma separated.
|
||||
|
||||
* `argAf =` - *Optional*, default value is empty,
|
||||
arguments of the function inserted
|
||||
*after* elements the second list.
|
||||
If multiple should be comma separated.
|
||||
|
||||
* `format=` - *Optional*, default value is empty,
|
||||
indicates a format which should be used
|
||||
to format the result, does not work when
|
||||
the `operator=` is used.
|
||||
|
||||
* `result=` - *Optional*, default value is empty,
|
||||
indicates a name of newly created macroarray,
|
||||
by default created macroarray name is concatenation
|
||||
of first 13 characters of names of arrays used
|
||||
to create the new one.
|
||||
|
||||
* `macarray=N` - *Optional*, default value is `N`,
|
||||
if set to `Y`/`YES` then a macro, named with
|
||||
the array name, is compiled to create convenient
|
||||
envelope for multiple ampersands, see the
|
||||
`%array()` macro for details.
|
||||
|
||||
* `reuse=Y` - *Optional*, default value is `Y`,
|
||||
when one of the arrays is shorter then elements
|
||||
are *reused* starting from the beginning.
|
||||
If `CP` then function is executed on the *Cartesian
|
||||
product* of arrays elements. Any other value will
|
||||
cut the process with the end of the shorter array.
|
||||
See examples for the details.
|
||||
|
||||
### EXAMPLES AND USECASES: ####################################################
|
||||
|
||||
See examples in `%zipArrays()` help for the details.
|
||||
|
||||
---
|
||||
|
||||
## >>> `%zipArrays()` macro: <<< <a name="ziparrays-macro"></a> #######################
|
||||
|
||||
The zipArrays() and QzipArrays() macros
|
||||
allow to use a function on elements of pair of
|
||||
macroarrays.
|
||||
|
||||
For two macroarrays the corresponding
|
||||
elements are taken and the macro applies a function, provided by user,
|
||||
to calculate result of the function on taken elements.
|
||||
|
||||
When one of the arrays is shorter then elements are, by default,
|
||||
"reused" starting from the beginning. But this behaviour can be altered.
|
||||
See examples for the details.
|
||||
|
||||
By default newly created macroarray name is concatenation
|
||||
of first 13 characters of names of arrays used to create the new one,
|
||||
e.g. if arrays names are `abc` and `def` then the result name is `abcdef`,
|
||||
if arrays names are `abcd1234567890` and `efgh1234567890` then the result
|
||||
name is `abcd123456789efgh123456789`
|
||||
|
||||
The `zipArrays()` returns unquoted value [by `%unquote()`].
|
||||
The `QzipArrays()` returns quoted value [by `%superq()`].
|
||||
|
||||
See examples below for the details.
|
||||
|
||||
The `%zipArrays()` macro executes like a pure macro code.
|
||||
|
||||
### SYNTAX: ###################################################################
|
||||
|
||||
The basic syntax is the following, the `<...>` means optional parameters:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
%zipArrays(
|
||||
first
|
||||
,second
|
||||
<,function=>
|
||||
<,operator=>
|
||||
<,argBf=>
|
||||
<,argMd=>
|
||||
<,argAf=>
|
||||
<,format=>
|
||||
<,result=>
|
||||
<,macarray=>
|
||||
<,reuse=>
|
||||
)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
**Arguments description**:
|
||||
|
||||
1. `first` - *Required*, a space separated list of texts.
|
||||
|
||||
2. `second` - *Required*, a space separated list of texts.
|
||||
|
||||
* `function = cat` - *Optional*, default value is `cat`,
|
||||
a function which will be applied
|
||||
to corresponding pairs of elements of
|
||||
the first and the second list.
|
||||
|
||||
* `operator =` - *Optional*, default value is empty,
|
||||
arithmetic infix operator used with elements
|
||||
the first and the second list. The first
|
||||
list is used on the left side of the operator
|
||||
the second list is used on the right side
|
||||
of the operator.
|
||||
|
||||
* `argBf =` - *Optional*, default value is empty,
|
||||
arguments of the function inserted
|
||||
*before* elements the first list.
|
||||
If multiple should be comma separated.
|
||||
|
||||
* `argMd =` - *Optional*, default value is empty,
|
||||
arguments of the function inserted
|
||||
*between* elements the first list and
|
||||
the second list.
|
||||
If multiple should be comma separated.
|
||||
|
||||
* `argAf =` - *Optional*, default value is empty,
|
||||
arguments of the function inserted
|
||||
*after* elements the second list.
|
||||
If multiple should be comma separated.
|
||||
|
||||
* `format=` - *Optional*, default value is empty,
|
||||
indicates a format which should be used
|
||||
to format the result, does not work when
|
||||
the `operator=` is used.
|
||||
|
||||
* `result=` - *Optional*, default value is empty,
|
||||
indicates a name of newly created macroarray,
|
||||
by default created macroarray name is concatenation
|
||||
of first 13 characters of names of arrays used
|
||||
to create the new one.
|
||||
|
||||
* `macarray=N` - *Optional*, default value is `N`,
|
||||
if set to `Y`/`YES` then a macro, named with
|
||||
the array name, is compiled to create convenient
|
||||
envelope for multiple ampersands, see the
|
||||
`%array()` macro for details.
|
||||
|
||||
* `reuse=Y` - *Optional*, default value is `Y`,
|
||||
when one of the arrays is shorter then elements
|
||||
are *reused* starting from the beginning.
|
||||
If `CP` then function is executed on the *Cartesian
|
||||
product* of arrays elements. Any other value will
|
||||
cut the process with the end of the shorter array.
|
||||
See examples for the details.
|
||||
|
||||
### EXAMPLES AND USECASES: ####################################################
|
||||
|
||||
**EXAMPLE 1.** Simple concatenation of elements:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
%array(a[*] x1-x3 (1:3))
|
||||
%array(b[*] x1-x5 (11:15))
|
||||
|
||||
%put _user_;
|
||||
|
||||
%zipArrays(a, b);
|
||||
%put _user_;
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
**EXAMPLE 2.** Shorter list is "reused":
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
%array(a[6] (1:6))
|
||||
%array(b[3] (10 20 30))
|
||||
|
||||
%zipArrays(a, b, result=A_and_B, macarray=Y);
|
||||
%put %do_over(A_and_B);
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
**EXAMPLE 3.** Use of the `operator=`:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
%array(c[0:4] (000 100 200 300 400))
|
||||
%array(d[2:16] (1002:1016))
|
||||
|
||||
%zipArrays(c, d, operator=+, result=C_plus_D, macarray=Y);
|
||||
%put (%do_over(C_plus_D));
|
||||
|
||||
%put %C_plus_D(1);
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
**EXAMPLE 4.** If one of array names is empty or an array does not exist:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
%array(a[6] (1:6))
|
||||
%array(b[3] (10 20 30))
|
||||
|
||||
%zipArrays(a, );
|
||||
%zipArrays(, b);
|
||||
|
||||
%zipArrays(a, z);
|
||||
%zipArrays(z, b);
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
**EXAMPLE 5.** Use of the `function=`:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
%array(one[3] A B C, vnames=Y)
|
||||
%array(two[5] p q r s t, vnames=Y)
|
||||
|
||||
%zipArrays(
|
||||
one
|
||||
,two
|
||||
,function = catx
|
||||
,argBf = %str( )
|
||||
,format = $quote.
|
||||
,macarray=Y
|
||||
)
|
||||
%put %do_over(onetwo);
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
**EXAMPLE 6.** To reuse or not to reuse, or maybe Cartesian product:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
%array(e[3] (10 20 30))
|
||||
%array(f[2] (5:6))
|
||||
|
||||
%zipArrays(e, f, reuse=n, operator=+, macarray=Y, result=_noReuse);
|
||||
%zipArrays(e, f, reuse=y, operator=+, macarray=Y, result=_yesReuse);
|
||||
%zipArrays(e, f, reuse=cp, operator=+, macarray=Y, result=_cartProdReuse);
|
||||
|
||||
%put %do_over(_noReuse);
|
||||
%put %do_over(_yesReuse);
|
||||
%put %do_over(_cartProdReuse);
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
**EXAMPLE 7.** Use middle argument:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
%array(yr[3] (2018:2020))
|
||||
%array(mth[12] (1:12))
|
||||
|
||||
%zipArrays(mth, yr, argMd=5, function=MDY, format=date11., macarray=Y);
|
||||
%put %do_over(mthyr);
|
||||
|
||||
%zipArrays(mth, yr, argMd=5, function=MDY, format=date11., macarray=Y, reuse=cp);
|
||||
%put %do_over(mthyr);
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
---
|
||||
|
||||
## >>> `%sortMacroArray()` macro: <<< <a name="sortmacroarray-macro"></a> #######################
|
||||
|
||||
The sortMacroArray() macro
|
||||
allow to sort elements of a macroarray.
|
||||
|
||||
The **limitation** is that sorted values are limited to 32767 bytes of length.
|
||||
|
||||
See examples below for the details.
|
||||
|
||||
### SYNTAX: ###################################################################
|
||||
|
||||
The basic syntax is the following, the `<...>` means optional parameters:
|
||||
~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
%sortMacroArray(
|
||||
array
|
||||
<,valLength=>
|
||||
<,outSet=>
|
||||
<,sortseq=>
|
||||
)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
**Arguments description**:
|
||||
|
||||
1. `array` - *Required*, name of an array generated by the `%array()` macro.
|
||||
|
||||
* `valLength = 32767` - *Optional*, default value is `32767`,
|
||||
maximum length of a variable storing macrovariable data.
|
||||
(the reason of 32767 limitation)
|
||||
|
||||
* `outSet = _NULL_` - *Optional*, default value is `_NULL_`,
|
||||
an optional output dataset name.
|
||||
|
||||
* `sortseq =` - *Optional*, default value is `LINGUISTIC(NUMERIC_COLLATION = ON)`,
|
||||
sorting options for use in an internal `Proc SORT`.
|
||||
|
||||
### EXAMPLES AND USECASES: ####################################################
|
||||
|
||||
|
||||
**EXAMPLE 1.** Basic use-case.
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
|
||||
options mprint;
|
||||
ods html;
|
||||
ods listing close;
|
||||
|
||||
|
||||
%array(hij [4:9] $ 512 ("C33" "B22" "A11" "A01" "A02" "X42"), macarray=Y)
|
||||
|
||||
%put NOTE: %do_over(hij);
|
||||
|
||||
%sortMacroArray(hij, valLength=3, outSet = A_NULL_(compress=char))
|
||||
|
||||
%put NOTE: %do_over(hij);
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
**EXAMPLE 2.** Basic use-case.
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
|
||||
options mprint;
|
||||
ods html;
|
||||
ods listing close;
|
||||
|
||||
|
||||
%array(ds = sashelp.class, vars = name|NNN height|h, macarray=Y)
|
||||
%array(ds = sashelp.cars, vars = model|, macarray=Y)
|
||||
|
||||
%put NOTE: %do_over(NNN);
|
||||
%put NOTE: %do_over(H);
|
||||
%put NOTE: %do_over(model);
|
||||
|
||||
%sortMacroArray(NNN, valLength=30, outSet = A_NULL_(compress=char))
|
||||
%sortMacroArray(H, valLength=32)
|
||||
%sortMacroArray(model, valLength=120)
|
||||
|
||||
%put NOTE: %do_over(NNN);
|
||||
%put NOTE: %do_over(H);
|
||||
%put NOTE: %do_over(model);
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
---
|
||||
|
||||
## License ####################################################################
|
||||
|
||||
Copyright (c) Bartosz Jablonski, since January 2019
|
||||
|
||||
Binary file not shown.
@@ -1,4 +1,4 @@
|
||||
- [The SQLinDS package [ver. 2.2]](#sqlinds-package)
|
||||
- [The SQLinDS package](#sqlinds-package)
|
||||
- [Content description](#content-description)
|
||||
* [library `dsSQL`](#library-dssql)
|
||||
* [`%dsSQL_inner()` macro](#dssql-inner-macro)
|
||||
@@ -8,16 +8,19 @@
|
||||
|
||||
---
|
||||
|
||||
# The SQLinDS package [ver. 2.2] <a name="sqlinds-package"></a> ###############################################
|
||||
# The SQLinDS package [ver. 2.3.0] <a name="sqlinds-package"></a> ###############################################
|
||||
|
||||
The **SQLinDS** package is an implementation of
|
||||
the *macro-function-sandwich* concept introduced in the
|
||||
*"Use the Full Power of SAS in Your Function-Style Macros"*,
|
||||
the article by *Mike Rhoads (Westat, Rockville)*.
|
||||
|
||||
Copy of the article is available at:
|
||||
The article is available at:
|
||||
[https://support.sas.com/resources/papers/proceedings12/004-2012.pdf](https://support.sas.com/resources/papers/proceedings12/004-2012.pdf)
|
||||
|
||||
Copy of the article can also be found in *additional content* directory.
|
||||
|
||||
|
||||
Package provides ability to *execute* SQL queries inside a data step, e.g.
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
data class;
|
||||
@@ -32,8 +35,9 @@ SQLinDS package contains the following components:
|
||||
|
||||
1. `%SQL()` macro - the main package macro available for the User
|
||||
2. `dsSQL()` function (internal)
|
||||
3. `%dsSQL_inner()` macro (internal)
|
||||
3. `%dsSQL_inner()` macro (internal)
|
||||
4. Library `DSSQL` (created as a subdirectory of the `WORK` library)
|
||||
5. Optional KMF-abbreviations `sqlinds`
|
||||
|
||||
---
|
||||
|
||||
@@ -42,14 +46,19 @@ Package contains:
|
||||
2. macro dssql_inner
|
||||
3. macro sql
|
||||
4. function dssql
|
||||
5. kmfsnip sqlinds
|
||||
|
||||
Required SAS Components:
|
||||
*Base SAS Software*
|
||||
|
||||
*SAS package generated by generatePackage, version 20201115*
|
||||
Package contains additional content, run: %loadPackageAddCnt(SQLinDS) to load it
|
||||
or look for the sqlinds_AdditionalContent directory in the Packages fileref
|
||||
localization (only if additional content was deployed during the installation process).
|
||||
|
||||
*SAS package generated by generatePackage, version 20231111*
|
||||
|
||||
The SHA256 hash digest for package SQLinDS:
|
||||
`CE1A266B9030E5E336B45F53DF483F6913FD8AE88A2884CEE88BEEF621FDBD78`
|
||||
`F*3C010734B76CA7459C4D35087C899121011CD4AA2932B56335FF11A805C8EF8D`
|
||||
|
||||
---
|
||||
# Content description ############################################################################################
|
||||
@@ -96,6 +105,8 @@ Based on the article *"Use the Full Power of SAS in Your Function-Style Macros"*
|
||||
by *Mike Rhoads* (Westat, Rockville), available at:
|
||||
[https://support.sas.com/resources/papers/proceedings12/004-2012.pdf](https://support.sas.com/resources/papers/proceedings12/004-2012.pdf)
|
||||
|
||||
Copy of the article can also be found in *additional content* directory.
|
||||
|
||||
### SYNTAX: ###################################################################
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~sas
|
||||
%sql(<nonempty sql querry code>)
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user