From d6e318869e79f6004ec6f94d7eba9b5afd17ec10 Mon Sep 17 00:00:00 2001 From: rd2 Date: Tue, 15 Aug 2023 21:40:23 -0400 Subject: [PATCH] Revises docs (namely for Yard) --- .github/workflows/pull_request.yml | 84 +--------- README.md | 68 ++++---- lib/oslg/oslog.rb | 256 +++++++++++++++-------------- lib/oslg/version.rb | 2 +- oslg.gemspec | 4 +- 5 files changed, 173 insertions(+), 241 deletions(-) diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index 1ac92c9..bcd3b52 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -6,7 +6,7 @@ on: - dev jobs: - test_300x: + test_oslg: runs-on: ubuntu-22.04 steps: - name: Check out repository @@ -15,88 +15,6 @@ jobs: 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: - 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.6.1 - docker run --name test --rm -d -t -v $(pwd):/work -w /work nrel/openstudio:3.6.1 docker exec -t test pwd docker exec -t test ls docker exec -t test bundle update diff --git a/README.md b/README.md index 2ce2569..0d0c4e6 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ # 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 module, 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 file). __oslg__ has no OpenStudio dependency, however; 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') @@ -14,7 +14,7 @@ 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. 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. ### Recommended use @@ -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? @@ -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") @@ -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| @@ -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) @@ -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 or inapplicable objects: ``` -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 invalid object, '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) @@ -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. uninitialized _ThermalZone_ object of an _OpenStudio Space_): ``` -return M.empty("faces", "sum", M::ERROR, false) if faces.empty? +return M.empty("zone", "conditioned?") 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 DEBUG log message (before returning _nil_): ``` -"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_): ``` -"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. --- diff --git a/lib/oslg/oslog.rb b/lib/oslg/oslog.rb index 70c0d60..04083cb 100644 --- a/lib/oslg/oslog.rb +++ b/lib/oslg/oslog.rb @@ -29,42 +29,27 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. module OSlg - DEBUG = 1 - INFO = 2 - WARN = 3 - ERROR = 4 - FATAL = 5 - - @@logs = [] - @@level = INFO - @@status = 0 - - @@tag = [] - @@tag[0 ] = "" - @@tag[DEBUG] = "DEBUG" - @@tag[INFO ] = "INFO" - @@tag[WARN ] = "WARNING" - @@tag[ERROR] = "ERROR" - @@tag[FATAL] = "FATAL" - - @@msg = [] - @@msg[0 ] = "" - @@msg[DEBUG] = "Debugging ..." - @@msg[INFO ] = "Success! No errors, no warnings" - @@msg[WARN ] = "Partial success, raised non-fatal warnings" - @@msg[ERROR] = "Partial success, encountered non-fatal errors" - @@msg[FATAL] = "Failure, triggered fatal errors" + DEBUG = 1 # e.g. for debugging e.g. "argument String? expecting Integer" + INFO = 2 # e.g. informative e.g. "success! no errors, no warnings" + WARN = 3 # e.g. warnings e.g. "partial success, see non-fatal warnings" + ERROR = 4 # e.g. erros e.g. "partial success, see non-fatal errors" + FATAL = 5 # e.g. failures e.g. "stopping! encountered fatal errors" + + # each log is a Hash with keys :level (Integer) and :message (String) + @@logs = [] + @@level = INFO # initial log level + @@status = 0 # initial status ## - # Return log entries. + # Returns log entries. # - # @return [Array] current log entries + # @return [Array] log entries (see @@logs) def logs @@logs end ## - # Return current log level. + # Returns current log level. # # @return [Integer] DEBUG, INFO, WARN, ERROR or FATAL def level @@ -72,7 +57,7 @@ def level end ## - # Return current log status. + # Returns current log status. # # @return [Integer] DEBUG, INFO, WARN, ERROR or FATAL def status @@ -80,7 +65,7 @@ def status end ## - # Return whether current status is DEBUG + # Returns whether current status is DEBUG. # # @return [Bool] true if DEBUG def debug? @@ -88,7 +73,7 @@ def debug? end ## - # Return whether current status is INFO + # Returns whether current status is INFO. # # @return [Bool] true if INFO def info? @@ -96,7 +81,7 @@ def info? end ## - # Return whether current status is WARN + # Returns whether current status is WARN. # # @return [Bool] true if WARN def warn? @@ -104,7 +89,7 @@ def warn? end ## - # Return whether current status is ERROR + # Returns whether current status is ERROR. # # @return [Bool] true if ERROR def error? @@ -112,7 +97,7 @@ def error? end ## - # Return whether current status is FATAL + # Returns whether current status is FATAL. # # @return [Bool] true if FATAL def fatal? @@ -120,66 +105,61 @@ def fatal? end ## - # Return string equivalent of level + # Resets level, if lvl (input) is within accepted range. # - # @param level [Integer] DEBUG, INFO, WARN, ERROR or FATAL + # @param lvl [#to_i] DEBUG, INFO, WARN, ERROR or FATAL # - # @return [String] "DEBUG", "INFO", "WARN", "ERROR" or "FATAL" - def tag(level) - return @@tag[level] if level >= DEBUG && level <= FATAL - - "" - end + # @return [Integer] updated/current level + def reset(lvl = DEBUG) + return @@level unless lvl.respond_to?(:to_i) - ## - # Return preset OSlg message linked to status. - # - # @param status [Integer] DEBUG, INFO, WARN, ERROR or FATAL - # - # @return [String] preset OSlg message - def msg(status) - return @@msg[status] if status >= DEBUG && status <= FATAL + lvl = lvl.to_i + return @@level if lvl < DEBUG + return @@level if lvl > FATAL - "" + @@level = lvl end ## - # Set level. - # - # @param level [Integer] DEBUG, INFO, WARN, ERROR or FATAL + # Logs a new entry, if provided arguments are valid. # - # @return [Integer] current level - def reset(level) - @@level = level if level >= DEBUG && level <= FATAL - end - - ## - # Log new entry. + # @param lvl [#to_i] DEBUG, INFO, WARN, ERROR or FATAL + # @param message [#to_s] user-provided log message # - # @param level [Integer] DEBUG, INFO, WARN, ERROR or FATAL - # @param message [String] user-provided message + # @example A user warning + # log(WARN, "Surface area < 100cm2") # - # @return [Integer] current status - def log(level = DEBUG, message = "") - if level >= DEBUG && level <= FATAL && level >= @@level - @@logs << {level: level, message: message} - @@status = level if level > @@status - end + # @return [Integer] updated/current status + def log(lvl = DEBUG, message = "") + return @@status unless lvl.respond_to?(:to_i) + return @@status unless message.respond_to?(:to_s) - @@status + lvl = lvl.to_i + message = message.to_s.strip + return @@status if lvl < DEBUG + return @@status if lvl > FATAL + return @@status if lvl < @@level + + @@logs << {level: lvl, message: message} + return @@status unless lvl > @@status + + @@status = lvl end ## - # Log template 'invalid object' message and return user-set object. + # Logs template 'invalid object' message, if provided arguments are valid. # - # @param id [String] invalid object identifier - # @param mth [String] calling method identifier - # @param ord [Integer] calling method argument order number of obj (optional) - # @param lvl [Integer] DEBUG, INFO, WARN, ERROR or FATAL (optional) - # @param res [Object] what to return (optional) + # @param id [#to_s] 'invalid object' identifier + # @param mth [#to_s] calling method identifier + # @param ord [#to_i] calling method argument order number of obj (optional) + # @param lvl [#to_i] DEBUG, INFO, WARN, ERROR or FATAL + # @param res what to return (optional) + # + # @example An invalid argument, logging a FATAL error, returning FALSE + # return invalid("area", "sum", 0, FATAL, false) if area > 1000000 # - # @return [Object] return object if specified by user - # @return [Nil] nil if return object undefined + # @return user-provided object + # @return [nil] if user hasn't provided an object to return def invalid(id = "", mth = "", ord = 0, lvl = DEBUG, res = nil) return res unless id.respond_to?(:to_s) return res unless mth.respond_to?(:to_s) @@ -200,23 +180,31 @@ def invalid(id = "", mth = "", ord = 0, lvl = DEBUG, res = nil) msg = "Invalid '#{id}' " msg += "arg ##{ord} " if ord > 0 msg += "(#{mth})" - log(lvl, msg) if lvl >= DEBUG && lvl <= FATAL + return res if lvl < DEBUG + return res if lvl > FATAL + + log(lvl, msg) res end ## - # Log template 'instance/class mismatch' message and return user-set object. + # Logs template 'instance/class mismatch' message, if provided arguments are + # valid. The message is not logged if the provided object to evaluate is an + # actual instance of the target class. # - # @param id [String] mismatched object identifier - # @param obj [Object] object to validate + # @param id [#to_s] mismatched object identifier + # @param obj the object to validate # @param cl [Class] target class - # @param mth [String] calling method identifier - # @param lvl [Integer] DEBUG, INFO, WARN, ERROR or FATAL (optional) - # @param res [Object] what to return (optional) + # @param mth [#to_s] calling method identifier (optional) + # @param lvl [#to_i] DEBUG, INFO, WARN, ERROR or FATAL + # @param res what to return (optional) + # + # @example A mismatched argument instance/class + # mismatch("area", area, Float, "sum") unless area.is_a?(Numeric) # - # @return [Object] return object if specified by user - # @return [Nil] nil if return object undefined + # @return user-provided object + # @return [nil] if user hasn't provided an object to return def mismatch(id = "", obj = nil, cl = nil, mth = "", lvl = DEBUG, res = nil) return res unless id.respond_to?(:to_s) return res unless cl.is_a?(Class) @@ -224,8 +212,8 @@ def mismatch(id = "", obj = nil, cl = nil, mth = "", lvl = DEBUG, res = nil) return res unless mth.respond_to?(:to_s) return res unless lvl.respond_to?(:to_i) - mth = mth.to_s.strip id = id.to_s.strip + mth = mth.to_s.strip lvl = lvl.to_i id = id[0...60] + " ..." if id.length > 60 @@ -235,23 +223,30 @@ def mismatch(id = "", obj = nil, cl = nil, mth = "", lvl = DEBUG, res = nil) return res if mth.empty? msg = "'#{id}' #{obj.class}? expecting #{cl} (#{mth})" - log(lvl, msg) if lvl >= DEBUG && lvl <= FATAL + return res if lvl < DEBUG + return res if lvl > FATAL + + log(lvl, msg) res end ## - # Log template 'missing hash key' message and return user-set object. + # Logs template 'missing hash key' message, if provided arguments are valid. + # The message is not logged if the provided key exists. # - # @param id [String] Hash identifier + # @param id [#to_s] Hash identifier # @param hsh [Hash] hash to validate - # @param key [Object] missing key - # @param mth [String] calling method identifier - # @param lvl [Integer] DEBUG, INFO, WARN, ERROR or FATAL (optional) - # @param res [Object] what to return (optional) + # @param key missing key + # @param mth [#to_s] calling method identifier + # @param lvl [#to_i] DEBUG, INFO, WARN, ERROR or FATAL + # @param res what to return (optional) + # + # @example A missing Hash key + # hashkey("floor area", floor, :area, "sum") unless floor.key?(:area) # - # @return [Object] return object if specified by user - # @return [Nil] nil if return object undefined + # @return user-provided object + # @return [nil] if user hasn't provided an object to return def hashkey(id = "", hsh = {}, key = "", mth = "", lvl = DEBUG, res = nil) return res unless id.respond_to?(:to_s) return res unless hsh.is_a?(Hash) @@ -270,21 +265,27 @@ def hashkey(id = "", hsh = {}, key = "", mth = "", lvl = DEBUG, res = nil) return res if mth.empty? msg = "Missing '#{key}' key in '#{id}' Hash (#{mth})" - log(lvl, msg) if lvl >= DEBUG && lvl <= FATAL + return res if lvl < DEBUG + return res if lvl > FATAL + + log(lvl, msg) res end ## - # Log template 'empty (uninitialized)' message and return user-set object. + # Logs template 'empty' message, if provided arguments are valid. # - # @param id [String] empty object identifier - # @param mth [String] calling method identifier - # @param lvl [Integer] DEBUG, INFO, WARN, ERROR or FATAL (optional) - # @param res [Object] what to return (optional) + # @param id [#to_s] empty object identifier + # @param mth [#to_s] calling method identifier + # @param lvl [#to_i] DEBUG, INFO, WARN, ERROR or FATAL + # @param res what to return (optional) + # + # @example An uninitialized variable, logging an ERROR, returning FALSE + # empty("zone", "conditioned?", FATAL, false) if space.thermalZone.empty? # - # @return [Object] return object if specified by user - # @return [Nil] nil if return object undefined + # @return user-provided object + # @return [nil] if user hasn't provided an object to return def empty(id = "", mth = "", lvl = DEBUG, res = nil) return res unless id.respond_to?(:to_s) return res unless mth.respond_to?(:to_s) @@ -301,21 +302,27 @@ def empty(id = "", mth = "", lvl = DEBUG, res = nil) return res if mth.empty? msg = "Empty '#{id}' (#{mth})" - log(lvl, msg) if lvl >= DEBUG && lvl <= FATAL + return res if lvl < DEBUG + return res if lvl > FATAL + + log(lvl, msg) res end ## - # Log template 'near zero' message and return user-set object. + # Logs template 'zero' value message, if provided arguments are valid. # - # @param id [String] zero object identifier - # @param mth [String] calling method identifier - # @param lvl [Integer] DEBUG, INFO, WARN, ERROR or FATAL (optional) - # @param res [Object] what to return (optional) + # @param id [#to_s] zero object identifier + # @param mth [#to_s] calling method identifier + # @param lvl [#to_i] DEBUG, INFO, WARN, ERROR or FATAL + # @param res what to return (optional) + # + # @example A near-zero variable + # zero("floor area", "sum") if floor[:area].abs < TOL # - # @return [Object] return object if specified by user - # @return [Nil] nil if return object undefined + # @return user-provided object + # @return [nil] if user hasn't provided an object to return def zero(id = "", mth = "", lvl = DEBUG, res = nil) return res unless id.respond_to?(:to_s) return res unless mth.respond_to?(:to_s) @@ -333,21 +340,27 @@ def zero(id = "", mth = "", lvl = DEBUG, res = nil) return res if mth.empty? msg = "Zero '#{id}' (#{mth})" - log(lvl, msg) if lvl >= DEBUG && lvl <= FATAL + return res if lvl < DEBUG + return res if lvl > FATAL + + log(lvl, msg) res end ## - # Log template 'negative' message and return user-set object. + # Logs template 'negative' message, if provided arguments are valid. # - # @param id [String] negative object identifier + # @param id [#to_s] negative object identifier # @param mth [String] calling method identifier # @param lvl [Integer] DEBUG, INFO, WARN, ERROR or FATAL (optional) # @param res [Object] what to return (optional) # - # @return [Object] return object if specified by user - # @return [Nil] nil if return object undefined + # @example A negative variable + # negative("floor area", "sum") if floor[:area] < 0 + # + # @return user-provided object + # @return [nil] if user hasn't provided an object to return def negative(id = "", mth = "", lvl = DEBUG, res = nil) return res unless id.respond_to?(:to_s) return res unless mth.respond_to?(:to_s) @@ -365,13 +378,16 @@ def negative(id = "", mth = "", lvl = DEBUG, res = nil) return res if mth.empty? msg = "Negative '#{id}' (#{mth})" - log(lvl, msg) if lvl >= DEBUG && lvl <= FATAL + return res if lvl < DEBUG + return res if lvl > FATAL + + log(lvl, msg) res end ## - # Reset log status and entries. + # Resets log status and entries. # # @return [Integer] current level def clean! diff --git a/lib/oslg/version.rb b/lib/oslg/version.rb index 5b1fe4b..82bf87f 100644 --- a/lib/oslg/version.rb +++ b/lib/oslg/version.rb @@ -29,5 +29,5 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. module OSlg - VERSION = "0.2.7".freeze + VERSION = "0.2.8".freeze # OSlg version end diff --git a/oslg.gemspec b/oslg.gemspec index cbadcbd..603d9a0 100644 --- a/oslg.gemspec +++ b/oslg.gemspec @@ -15,8 +15,8 @@ Gem::Specification.new do |s| s.version = OSlg::VERSION s.license = "BSD-3-Clause" s.summary = "OpenStudio SDK logger" - s.description = "For OpenStudio SDK users who wish to select " \ - "what gets logged to which target." + s.description = "For OpenStudio SDK users (or others) who wish "\ + "to select what gets logged to which target." s.authors = ["Denis Bourgeois"] s.email = ["denis@rd2.ca"] s.platform = Gem::Platform::RUBY