Skip to content

Commit

Permalink
Merge pull request #11 from rd2/yard
Browse files Browse the repository at this point in the history
Revises docs (namely for Yard)
  • Loading branch information
brgix authored Aug 17, 2023
2 parents a46b432 + 8ddf04f commit 3a8d1ee
Show file tree
Hide file tree
Showing 5 changed files with 175 additions and 241 deletions.
82 changes: 1 addition & 81 deletions .github/workflows/pull_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,87 +6,7 @@ on:
- dev

jobs:
test_300x:
runs-on: ubuntu-22.04
steps:
- name: Check out repository
uses: actions/checkout@v2
- name: Run Tests
run: |
echo $(pwd)
echo $(ls)
docker pull nrel/openstudio:3.0.0
docker run --name test --rm -d -t -v $(pwd):/work -w /work nrel/openstudio:3.0.0
docker exec -t test pwd
docker exec -t test ls
docker exec -t test bundle update
docker exec -t test bundle exec rake
docker kill test
test_321x:
runs-on: ubuntu-22.04
steps:
- name: Check out repository
uses: actions/checkout@v2
- name: Run Tests
run: |
echo $(pwd)
echo $(ls)
docker pull nrel/openstudio:3.2.1
docker run --name test --rm -d -t -v $(pwd):/work -w /work nrel/openstudio:3.2.1
docker exec -t test pwd
docker exec -t test ls
docker exec -t test bundle update
docker exec -t test bundle exec rake
docker kill test
test_330x:
runs-on: ubuntu-22.04
steps:
- name: Check out repository
uses: actions/checkout@v2
- name: Run Tests
run: |
echo $(pwd)
echo $(ls)
docker pull nrel/openstudio:3.3.0
docker run --name test --rm -d -t -v $(pwd):/work -w /work nrel/openstudio:3.3.0
docker exec -t test pwd
docker exec -t test ls
docker exec -t test bundle update
docker exec -t test bundle exec rake
docker kill test
test_340x:
runs-on: ubuntu-22.04
steps:
- name: Check out repository
uses: actions/checkout@v2
- name: Run Tests
run: |
echo $(pwd)
echo $(ls)
docker pull nrel/openstudio:3.4.0
docker run --name test --rm -d -t -v $(pwd):/work -w /work nrel/openstudio:3.4.0
docker exec -t test pwd
docker exec -t test ls
docker exec -t test bundle update
docker exec -t test bundle exec rake
docker kill test
test_351x:
runs-on: ubuntu-22.04
steps:
- name: Check out repository
uses: actions/checkout@v2
- name: Run Tests
run: |
echo $(pwd)
echo $(ls)
docker pull nrel/openstudio:3.5.1
docker run --name test --rm -d -t -v $(pwd):/work -w /work nrel/openstudio:3.5.1
docker exec -t test pwd
docker exec -t test ls
docker exec -t test bundle update
docker exec -t test bundle exec rake
docker kill test
test_361x:
test_oslg:
runs-on: ubuntu-22.04
steps:
- name: Check out repository
Expand Down
72 changes: 35 additions & 37 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
# oslg

A logger module for _picky_ [OpenStudio](https://openstudio.net) [Measure](https://nrel.github.io/OpenStudio-user-documentation/reference/measure_writing_guide/) developers who wish to select what gets logged to which target (e.g. OpenStudio _runner_ vs custom JSON file). Add:
A logger, initially for _picky_ [OpenStudio](https://openstudio.net) [Measure](https://nrel.github.io/OpenStudio-user-documentation/reference/measure_writing_guide/) developers who wish to select what gets logged to which target (e.g. OpenStudio _runner_ vs custom JSON files). Yet __oslg__ has no OpenStudio dependency; it can be integrated within any other environment. Just add:

```
gem "oslg", git: "https://github.com/rd2/oslg", branch: "main"
```

... in a v2.1 [bundled](https://bundler.io) _Measure_ development environment "Gemfile" (or instead as a _gemspec_ dependency), and then run:
... in a v2.1 [bundled](https://bundler.io) development environment "Gemfile" (or instead as a _gemspec_ dependency), and then run:

```
bundle install (or 'bundle update')
```

### OpenStudio & EnergyPlus

In most cases, critical (and many non-critical) OpenStudio anomalies will be caught by EnergyPlus at the start of a simulation. Standalone applications (e.g. _Apply Measures Now_) or [SDK](https://openstudio-sdk-documentation.s3.amazonaws.com/index.html)-based iterative solutions can't rely on EnergyPlus to catch such errors - and somehow warn users of potentially invalid results. This Ruby module provides developers a means to log warnings, as well as non-fatal & fatal errors, that may eventually put OpenStudio's (or EnergyPlus') internal processes at risk. Developers are free to decide how to harness __oslg__ as they see fit, e.g. output logged WARNING messages to the OpenStudio _runner_, while writing out DEBUG messages to a bug report file.
In most cases, critical (and many non-critical) OpenStudio anomalies will be caught by EnergyPlus at the start of a simulation. Standalone applications (e.g. _Apply Measures Now_) or [SDK](https://openstudio-sdk-documentation.s3.amazonaws.com/index.html) based iterative solutions can't rely on EnergyPlus to catch such errors - and somehow warn users of potentially invalid results. __oslg__ provides developers a means to log warnings, as well as non-fatal & fatal errors, that may eventually put OpenStudio's (or EnergyPlus') internal processes at risk. Developers are free to decide how to harness __oslg__ as they see fit, e.g. output logged WARNING messages to the OpenStudio _runner_, while writing out DEBUG messages to a bug report file.

### Recommended use

Expand All @@ -39,7 +39,7 @@ FATAL

DEBUG messages aren't benign at all, but are certainly less informative for the typical Measure user.

Initially, __oslg__ sets 2x internal attributes: `level` (INFO) and `status` (< DEBUG). The `level` attribute is a user-set threshold below which less severe logs (e.g. DEBUG) are ignored. For instance, if `level` were _reset_ to DEBUG (e.g. `M.reset(M::DEBUG)`), then all DEBUG messages would also be logged. The `status` attribute is reset with each new log entry when the latter's log level is more severe than its predecessors (e.g. `status == M::FATAL` if there is a single log entry registered as FATAL). To check the curent __oslg__ `status` (true or false):
Initially, __oslg__ sets 2 _global_ internal attributes: `level` (INFO) and `status` (< DEBUG). The `level` attribute is a user-set threshold below which less severe logs (e.g. DEBUG) are ignored. For instance, if `level` were _reset_ to DEBUG (e.g. `M.reset(M::DEBUG)`), then all DEBUG messages would also be logged. The `status` attribute is reset with each new log entry when the latter's log level is more severe than its predecessors (e.g. `status == M::FATAL` if there is a single log entry registered as FATAL). To check the curent __oslg__ `status` (true or false):

```
M.debug?
Expand All @@ -54,7 +54,7 @@ It's sometimes not a bad idea to rely on a _clean_ slate (e.g. within RSpecs). T
M.clean!
```

EnergyPlus will run with e.g. out-of-range material or fluid properties, while logging ERROR messages in the process. It remains up to users to decide what to do with simulation results. We recommend something similar with __oslg__. For instance, we suggest logging as __FATAL__ any error that should halt Measure processes and prevent OpenStudio from launching an EnergyPlus simulation. This could be missing or poorly-defined OpenStudio files.
EnergyPlus will run with e.g. out-of-range material or fluid properties, while logging ERROR messages in the process. It remains up to users to decide what to do with simulation results. We recommend something similar with __oslg__. For instance, we suggest logging as __FATAL__ any error that should halt Measure processes and prevent OpenStudio from launching an EnergyPlus simulation. This could be missing or poorly formatted files.

```
M.log(M::FATAL, "Missing input JSON file")
Expand All @@ -66,7 +66,7 @@ Consider logging non-fatal __ERROR__ messages when encountering invalid OpenStud
M.log(M::ERROR, "Measure won't process MASSLESS materials")
```

A __WARNING__ could be triggered from inherit limitations of the underlying Measure scope or methodology (something users may have little knowledge of beforehand). For instance, surfaces the size of dinner plates are often artifacts of poor 3D model design. It's usually not a good idea to have such small surfaces in an OpenStudio model, but neither OpenStudio nor EnergyPlus will necessarily warn users of such occurrences. It's up to users to decide on the suitable course of action.
A __WARNING__ could be triggered from inherit limitations of the underlying Measure scope or methodology (something users may have little knowledge of beforehand). For instance, surfaces the size of dinner plates are often artifacts of poor 3D modelling. It's usually not a good idea to have such small surfaces in an OpenStudio model, but neither OpenStudio nor EnergyPlus will necessarily warn users of such occurrences. It's up to users to decide on the suitable course of action.

```
M.log(M::WARN, "Surface area < 100cm2")
Expand All @@ -78,13 +78,13 @@ There's also the possibility of logging __INFO__-rmative messages for users, e.g
M.log(M::INFO, "Envelope compliant to prescriptive code requirements")
```

Finally, a number of sanity checks are likely warranted to ensure Ruby doesn't crash (e.g., invalid access to uninitialized variables), especially for lower-level functions. We suggest implementing safe fallbacks when this occurs, but __DEBUG__ errors could nonetheless be triggered to signal a bug.
Finally, a number of sanity checks are likely warranted to ensure Ruby doesn't crash (e.g., invalid access to uninitialized variables), especially for lower-level functions. We suggest implementing safe fallbacks when this occurs, but __DEBUG__ errors could nonetheless be logged to signal buggy code.

```
M.log(M::DEBUG, "Hash? expecting Array (method)")
```

All log entries are stored in a single Ruby _Array_, with each individual log entry as a Ruby _Hash_ with 2x _keys_ ```:level``` and ```:message```, e.g.:
All log entries are stored in a single Ruby _Array_, with each individual log entry as a Ruby _Hash_ with 2 _keys_ ```:level``` and ```:message```, e.g.:

```
M.logs.each do |log|
Expand All @@ -96,7 +96,7 @@ These logs can be first _mapped_ to other structures (then edited), depending on

### Preset log templates

Typically, developers would first catch bad input, log an error message and possibly exit by returning an object (e.g. __false__, __nil__), e.g.:
Typically, developers would first catch bad input, log an error message and possibly exit by returning an object (e.g. __false__, __nil__), such as:

```
unless var.is_a?(Array)
Expand All @@ -109,19 +109,19 @@ The following are __oslg__ one-liner methods that _log & return_ in one go. Thes

---

__invalid__: for logging e.g. uninitialized or nilled objects:
__invalid__: for logging e.g. nilled objects or out-of-scope variables:

```
return M.invalid("area", "sum", 0, M::ERROR, false) unless area
return M.invalid("area", "sum", 0, M::FATAL, false) if area > 1000000
```

This logs an ERROR message informing users that an invalid object, 'area', was caught while running method 'sum', and then exits by returning _false_. The logged message would be:
This logs a FATAL error message informing users that an out-of-scope argument, 'area', was caught while running method 'sum', and then exits by returning _false_. The logged message would be:

```
"Invalid 'area' (sum)"
```

The 3rd argument (e.g. _0_) is ignored unless `> 0` - a useful option when asserting method arguments:
The 3rd parameter (e.g. _0_) is ignored unless `> 0` - a useful option when asserting method arguments:

```
def sum(areas, units)
Expand All @@ -131,93 +131,91 @@ def sum(areas, units)
end
```

... would generate the following if both `areas` and `units` arguments were for instance _nilled_:
... would generate the following if both `areas` and `units` arguments were, for instance, _nilled_:
```
"Invalid 'areas' arg #1 (sum)"
"Invalid 'units' arg #2 (sum)"
```

The first 2x __invalid__ method arguments (faulty object ID, calling method ID) are required. The remaining 3x arguments are optional; in such cases, __invalid__ `level` defaults to DEBUG, and __invalid__ returns _nil_).
The first 2 __invalid__ method parameters (faulty object ID, calling method ID) are required. The remaining 3 parameters are optional; in such cases, __invalid__ `level` defaults to DEBUG, and __invalid__ returns _nil_.

---

__mismatch__: for logging incompatible instances vs classes:

```
return M.mismatch("areas", areas, Array, "sum") unless areas.is_a?(Array)
return M.mismatch("area", area, Float, "sum") unless area.is_a?(Numeric)
```

If 'areas' were for example a _String_, __mismatch__ would generate the following DEBUG log message (before returning _nil_):
If 'area' were for example a _String_, __mismatch__ would generate the following DEBUG log message (before returning _nil_):

```
"'areas' String? expecting Array (sum)"
"'area' String? expecting Float (sum)"
```

These 4x __mismatch__ arguments are required (an object ID, a valid Ruby object, the mismatched Ruby class, and the calling method ID). As a safeguard, __oslg__ will NOT log a _mismatch_ if the object is an actual instance of the class. As with __invalid__, there are 2x optional _terminal_ arguments, e.g. `M::ERROR, false)`.
These 4 __mismatch__ parameters are required (an object ID, a valid Ruby object, the mismatched Ruby class, and the calling method ID). As a safeguard, __oslg__ will NOT log a _mismatch_ if the object is an actual instance of the class. As with __invalid__, there are 2 optional _terminal_ parameters (e.g. `M::FATAL`, `false`).

---

__hashkey__: for logging missing _Hash_ keys:

```
return M.hashkey("faces", faces, :area, "sum") unless faces.key?(:area)
return M.hashkey("floor area", floor, :area, "sum") unless floor.key?(:area)
```

If the _Hash_ `faces` does not hold `:area` as one of its keys, then __hashkey__ would generate the following DEBUG log message (before returning _nil_):
If the _Hash_ `floor` does not hold `:area` as one of its keys, then __hashkey__ would generate the following DEBUG log message (before returning _nil_):

```
"Missing 'area' key in 'faces' Hash (sum)"
"Missing 'area' key in 'floor' Hash (sum)"
```

Similar to __mismatch__, the method __hashkey__ requires 4x arguments (a _Hash_ ID, a valid Ruby _Hash_, the missing _key_, and the calling method ID). There are also 2x optional _terminal_ arguments, e.g. `M::ERROR, false)`.
Similar to __mismatch__, the method __hashkey__ requires 4 parameters (a _Hash_ ID, a valid Ruby _Hash_, the missing _key_, and the calling method ID). There are also 2 optional _terminal_ parameters (e.g. `M::FATAL`, `false`).

---

__empty__: for logging empty _Enumerable_ (e.g. _Array_, _Hash_) instances or uninitialized boost optionals (e.g. uninitialized _ThermalZone_ object of an _OpenStudio Space_):
__empty__: for logging empty _Enumerable_ (e.g. _Array_, _Hash_) instances or uninitialized _Boost_ optionals (e.g. an uninitialized _ThermalZone_ object of an _OpenStudio Space_):

```
return M.empty("faces", "sum", M::ERROR, false) if faces.empty?
return M.empty("zone", "conditioned?", M::FATAL, false) if space.thermalZone.empty?
```

An empty `faces` _Hash_ would generate the following ERROR log message (before returning _false_):
An empty (i.e. uninitialized) `thermalZone` would generate the following FATAL error log message (before returning _false_):

```
"Empty 'faces' (sum)"
"Empty 'zone' (conditioned?)"
```

Again, the first 2x arguments are required; the last 2x are optional.
Again, the first 2 parameters are required; the last 2 are optional.

---

__zero__: for logging zero'ed (or nearly-zero'ed) values:

```
M.zero("area", "sum", M::FATAL, false) if area.zero?
M.zero("area", "sum", M::FATAL, false) if area.abs < TOL
M.zero("floor area", "sum", M::FATAL, false) if floor[:area].abs < TOL
```
... generating the following FATAL log message (before returning _false_):
... generating the following FATAL error log message (before returning _false_):

```
"Zero 'area' (sum)"
"Zero 'area' (sum)"
"Zero 'floor area' (sum)"
```

And again, the first 2x arguments are required; the last 2x are optional.
And again, the first 2 parameters are required; the last 2 are optional.

---

__negative__: for logging negative (< 0) values:

```
M.negative("area", "sum", M::FATAL, false) if area < 0
M.negative("floor area", "sum", M::FATAL, false) if floor[:area] < 0
```
... generating this FATAL log message (before returning _false_):

```
"Negative 'area' (sum)"
"Negative 'floor area' (sum)"
```

You guessed it: the first 2x arguments are required; the last 2x as optionals.
You guessed it: the first 2 parameters are required; the last 2 as optionals.

---

Expand Down
Loading

0 comments on commit 3a8d1ee

Please sign in to comment.