oslg 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 0535a05d35fee722c018380a21e3253ce9764058b7092a80ac4904426c9fa243
4
+ data.tar.gz: 5919cb3f5ecb420a53c54b5740bf72177077cacb0a3a2cce65647ba12a8b4094
5
+ SHA512:
6
+ metadata.gz: 432dfef35fa88b722c2dff388ebe8f999e4a9bad0aaa987b495006c968572dac98773f5a7659866c3955620622b5b89a3c5544bdad1f577d3feba5bf51796fa5
7
+ data.tar.gz: 2696ecd29f72652774d0b6cf5db41a3e4b81af54c4d9a2cd8b64669500085c5d06914744ac061b42e878e3f27c6ac89387b094aeaf08f87b477fd9e2a2e8bef3
@@ -0,0 +1,72 @@
1
+ name: Pull Request CI
2
+
3
+ on:
4
+ pull_request:
5
+ branches:
6
+ - main
7
+
8
+ jobs:
9
+ test_300x:
10
+ runs-on: ubuntu-18.04
11
+ steps:
12
+ - name: Check out repository
13
+ uses: actions/checkout@v2
14
+ - name: Run Tests
15
+ run: |
16
+ echo $(pwd)
17
+ echo $(ls)
18
+ docker pull nrel/openstudio:3.0.0
19
+ docker run --name test --rm -d -t -v $(pwd):/work -w /work nrel/openstudio:3.0.0
20
+ docker exec -t test pwd
21
+ docker exec -t test ls
22
+ docker exec -t test bundle update
23
+ docker exec -t test bundle exec rake
24
+ docker kill test
25
+ test_321x:
26
+ runs-on: ubuntu-18.04
27
+ steps:
28
+ - name: Check out repository
29
+ uses: actions/checkout@v2
30
+ - name: Run Tests
31
+ run: |
32
+ echo $(pwd)
33
+ echo $(ls)
34
+ docker pull nrel/openstudio:3.2.1
35
+ docker run --name test --rm -d -t -v $(pwd):/work -w /work nrel/openstudio:3.2.1
36
+ docker exec -t test pwd
37
+ docker exec -t test ls
38
+ docker exec -t test bundle update
39
+ docker exec -t test bundle exec rake
40
+ docker kill test
41
+ test_330x:
42
+ runs-on: ubuntu-18.04
43
+ steps:
44
+ - name: Check out repository
45
+ uses: actions/checkout@v2
46
+ - name: Run Tests
47
+ run: |
48
+ echo $(pwd)
49
+ echo $(ls)
50
+ docker pull nrel/openstudio:3.3.0
51
+ docker run --name test --rm -d -t -v $(pwd):/work -w /work nrel/openstudio:3.3.0
52
+ docker exec -t test pwd
53
+ docker exec -t test ls
54
+ docker exec -t test bundle update
55
+ docker exec -t test bundle exec rake
56
+ docker kill test
57
+ test_340x:
58
+ runs-on: ubuntu-18.04
59
+ steps:
60
+ - name: Check out repository
61
+ uses: actions/checkout@v2
62
+ - name: Run Tests
63
+ run: |
64
+ echo $(pwd)
65
+ echo $(ls)
66
+ docker pull nrel/openstudio:3.4.0
67
+ docker run --name test --rm -d -t -v $(pwd):/work -w /work nrel/openstudio:3.4.0
68
+ docker exec -t test pwd
69
+ docker exec -t test ls
70
+ docker exec -t test bundle update
71
+ docker exec -t test bundle exec rake
72
+ docker kill test
data/.gitignore ADDED
@@ -0,0 +1,11 @@
1
+ Gemfile.lock
2
+ .rspec_status
3
+ .bundle
4
+ pkg
5
+
6
+ .yardoc
7
+ _yardoc
8
+ doc/
9
+ rdoc
10
+
11
+ .DS_Store
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,29 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2022, Denis Bourgeois
4
+ All rights reserved.
5
+
6
+ Redistribution and use in source and binary forms, with or without
7
+ modification, are permitted provided that the following conditions are met:
8
+
9
+ 1. Redistributions of source code must retain the above copyright notice, this
10
+ list of conditions and the following disclaimer.
11
+
12
+ 2. Redistributions in binary form must reproduce the above copyright notice,
13
+ this list of conditions and the following disclaimer in the documentation
14
+ and/or other materials provided with the distribution.
15
+
16
+ 3. Neither the name of the copyright holder nor the names of its
17
+ contributors may be used to endorse or promote products derived from
18
+ this software without specific prior written permission.
19
+
20
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/README.md ADDED
@@ -0,0 +1,220 @@
1
+ # oslg
2
+
3
+ A logger module for _picky_ [OpenStudio](https://openstudio-sdk-documentation.s3.amazonaws.com/index.html) [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:
4
+
5
+ ```
6
+ gem "oslg", git: "https://github.com/rd2/oslg", branch: "main"
7
+ ```
8
+
9
+ ... in a measure's development environment "Gemfile", and then run:
10
+
11
+ ```
12
+ bundle install
13
+ ```
14
+
15
+ ### OpenStudio & EnergyPlus
16
+
17
+ 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.
18
+
19
+ ### Recommended use
20
+
21
+ As a Ruby module, one can access __oslg__ by _extending_ a measure module or class:
22
+
23
+ ```
24
+ module Modu
25
+ extend OSlg
26
+ ...
27
+ end
28
+ ```
29
+
30
+ Ordered __oslg__ levels (or CONSTANTS), from benign to severe:
31
+
32
+ ```
33
+ DEBUG
34
+ INFO
35
+ WARN
36
+ ERROR
37
+ FATAL
38
+ ```
39
+
40
+ DEBUG messages aren't benign at all, but are certainly less informative for the typical Measure user.
41
+
42
+ Initially, __oslg__ sets 2x internal variable states: `level` (INFO) and `status` (< DEBUG). The variable `level` 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. `Modu.reset(Modu::DEBUG)`), then all DEBUG messages would also be logged. The variable `status` is reset with each new log entry if the latter's log level is more severe than its predecessor (e.g. `status == Modu::FATAL` if there is a single log entry registered as FATAL). To check the curent __oslg__ `status` (true or false):
43
+
44
+ ```
45
+ Modu.debug?
46
+ Modu.warn?
47
+ Modu.error?
48
+ Modu.fatal?
49
+ ```
50
+
51
+ It's sometimes not a bad idea to rely on a _clean_ slate (e.g. within RSpecs). This flushes out all previous logs and resets `level` (INFO) and `status` (< DEBUG) - use with caution in production code!
52
+
53
+ ```
54
+ Modu.clean!
55
+ ```
56
+
57
+ 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.
58
+
59
+ ```
60
+ Modu.log(Modu::FATAL, "Missing input JSON file")
61
+ ```
62
+
63
+ Consider logging non-fatal __ERROR__ messages when encountering invalid OpenStudio file entries, i.e. well-defined, yet invalid vis-à-vis EnergyPlus limitations. The invalid object could be simply ignored, while the measure pursues its (otherwise valid) calculations ... with OpenStudio ultimately launching an EnergyPlus simulation. If a simulation indeed ran (ultimately a go/no-go decision made by the EnergyPlus simulation engine), it would be up to users to decide if simulation results were valid or useful, given the context - maybe based on __oslg__ logged messages. In short, non-fatal ERROR logs should ideally point to bad input users can fix.
64
+
65
+ ```
66
+ Modu.log(Modu::ERROR, "Measure won't process MASSLESS materials")
67
+ ```
68
+
69
+ 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.
70
+
71
+ ```
72
+ Modu.log(Modu::WARN, "Surface area < 100cm2")
73
+ ```
74
+
75
+ There's also the possibility of logging __INFO__-rmative messages for users, e.g. the final state of a measure variable before exiting.
76
+
77
+ ```
78
+ Modu.log(Modu::INFO, "Envelope compliant to prescriptive code requirements")
79
+ ```
80
+
81
+ 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.
82
+
83
+ ```
84
+ Modu.log(Modu::DEBUG, "Hash? expecting Array (method)")
85
+ ```
86
+
87
+ 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.:
88
+
89
+ ```
90
+ Modu.logs.each do |log|
91
+ puts "Uh-oh: #{log[:message]}" if log[:level] > Modu::INFO
92
+ end
93
+ ```
94
+
95
+ These logs can be first _mapped_ to other structures (then edited), depending on output targets.
96
+
97
+ ### Preset log templates
98
+
99
+ Typically, developers would first catch bad input, log an error message and possibly exit by returning a variable (e.g. __false__, __nil__), e.g.:
100
+
101
+ ```
102
+ unless var.is_a?(Array)
103
+ Modu.log(Modu::DEBUG, "#{var.class}? expecting Array (method)")
104
+ return false
105
+ end
106
+ ```
107
+
108
+ The following are __oslg__ one-liner methods that _log & return_ in one go. These are for some of the most common checks OpenStudio SDK Ruby developers are likely to need. These methods require _valid_ arguments for __oslg__ to actually log. Although often expecting strings as arguments, the methods will try to convert other types to strings (e.g. classes, numbers, even entire arrays) if possible.
109
+
110
+ ---
111
+
112
+ __invalid__: for logging e.g. uninitialized or nilled objects:
113
+
114
+ ```
115
+ return Modu.invalid("area", "sum", 0, Modu::ERROR, false) unless area
116
+ ```
117
+
118
+ 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:
119
+
120
+ ```
121
+ "Invalid 'area' (sum)"
122
+ ```
123
+
124
+ The 3rd argument (e.g. _0_) is ignored unless `> 0` - a useful option when asserting method arguments:
125
+
126
+ ```
127
+ def sum(areas, units)
128
+ return Modu.invalid("areas", "sum", 1) unless areas
129
+ return Modu.invalid("units", "sum", 2) unless units
130
+ ...
131
+ end
132
+ ```
133
+
134
+ ... would generate the following if both `areas` and `units` arguments were nilled:
135
+ ```
136
+ "Invalid 'areas' arg #1 (sum)"
137
+ "Invalid 'units' arg #2 (sum)"
138
+ ```
139
+
140
+ 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_).
141
+
142
+ ---
143
+
144
+ __mismatch__: for logging incompatible instances vs classes:
145
+
146
+ ```
147
+ return Modu.mismatch("areas", areas, Array, "sum") unless areas.is_a?(Array)
148
+ ```
149
+
150
+ If 'areas' were a _String_, __mismatch__ would generate the following DEBUG log message (before returning _nil_):
151
+
152
+ ```
153
+ "'areas' String? expecting Array (sum)"
154
+ ```
155
+
156
+ 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. `Modu::ERROR, false)`.
157
+
158
+ ---
159
+
160
+ __hashkey__: for logging missing _Hash_ keys:
161
+
162
+ ```
163
+ return Modu.hashkey("faces", faces, :area, "sum") unless faces.key?(:area)
164
+ ```
165
+
166
+ If the _Hash_ `faces` does not hold `:area` as one of its keys, then __mismatch__ would generate the following DEBUG log message (before returning _nil_):
167
+
168
+ ```
169
+ "'faces' Hash: no key 'area' (sum)"
170
+ ```
171
+
172
+ 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. `Modu::ERROR, false)`.
173
+
174
+ ---
175
+
176
+ __empty__: for logging empty _Enumerable_ (e.g. _Array_, _Hash_) instances or uninitialized boost optionals (e.g. uninitialized _ThermalZone_ object of an _OpenStudio Space_):
177
+
178
+ ```
179
+ return Modu.empty("faces", "sum", Modu::ERROR, false) if faces.empty?
180
+ ```
181
+
182
+ An empty `faces` _Hash_ would generate the following ERROR log message (before returning _false_):
183
+
184
+ ```
185
+ "Empty 'faces' (sum)"
186
+ ```
187
+
188
+ Again, the first 2x arguments are required; the last 2x are optional.
189
+
190
+ ---
191
+
192
+ __zero__: for logging zero'ed (or nearly-zero'ed) values:
193
+
194
+ ```
195
+ Modu.zero("area", "sum", Modu::FATAL, false) if area.zero?
196
+ Modu.zero("area", "sum", Modu::FATAL, false) if area.abs < TOL
197
+ ```
198
+ ... generating the following FATAL log message (before returning _false_):
199
+
200
+ ```
201
+ "'area' ~zero (sum)"
202
+ "'area' ~zero (sum)"
203
+ ```
204
+
205
+ And again, the first 2x arguments are required; the last 2x are optional.
206
+
207
+ ---
208
+
209
+ __negative__: for logging negative (< 0) values:
210
+
211
+ ```
212
+ Modu.negative("area", "sum", Modu::FATAL, false) if area < 0
213
+ ```
214
+ ... generating this FATAL log message (before returning _false_):
215
+
216
+ ```
217
+ "'area' negative (sum)"
218
+ ```
219
+
220
+ You guessed it: the first 2x arguments are required; the last 2x as optionals.
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ require "yard"
7
+ YARD::Rake::YardocTask.new do |t|
8
+ t.files = ["lib/oslg/oslog.rb"]
9
+ end
10
+
11
+ task default: :spec
data/lib/oslg/oslog.rb ADDED
@@ -0,0 +1,364 @@
1
+ # BSD 3-Clause License
2
+ #
3
+ # Copyright (c) 2022, Denis Bourgeois
4
+ # All rights reserved.
5
+ #
6
+ # Redistribution and use in source and binary forms, with or without
7
+ # modification, are permitted provided that the following conditions are met:
8
+ #
9
+ # 1. Redistributions of source code must retain the above copyright notice, this
10
+ # list of conditions and the following disclaimer.
11
+ #
12
+ # 2. Redistributions in binary form must reproduce the above copyright notice,
13
+ # this list of conditions and the following disclaimer in the documentation
14
+ # and/or other materials provided with the distribution.
15
+ #
16
+ # 3. Neither the name of the copyright holder nor the names of its
17
+ # contributors may be used to endorse or promote products derived from
18
+ # this software without specific prior written permission.
19
+ #
20
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24
+ # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27
+ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28
+ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
+
31
+ module OSlg
32
+ DEBUG = 1
33
+ INFO = 2
34
+ WARN = 3
35
+ ERROR = 4
36
+ FATAL = 5
37
+
38
+ @@logs = []
39
+ @@level = INFO
40
+ @@status = 0
41
+
42
+ @@tag = []
43
+ @@tag[0 ] = ""
44
+ @@tag[DEBUG] = "DEBUG"
45
+ @@tag[INFO ] = "INFO"
46
+ @@tag[WARN ] = "WARNING"
47
+ @@tag[ERROR] = "ERROR"
48
+ @@tag[FATAL] = "FATAL"
49
+
50
+ @@msg = []
51
+ @@msg[0 ] = ""
52
+ @@msg[DEBUG] = "Debugging ..."
53
+ @@msg[INFO ] = "Success! No errors, no warnings"
54
+ @@msg[WARN ] = "Partial success, raised non-fatal warnings"
55
+ @@msg[ERROR] = "Partial success, encountered non-fatal errors"
56
+ @@msg[FATAL] = "Failure, triggered fatal errors"
57
+
58
+ ##
59
+ # Return log entries.
60
+ #
61
+ # @return [Array] current log entries
62
+ def logs
63
+ @@logs
64
+ end
65
+
66
+ ##
67
+ # Return current log level.
68
+ #
69
+ # @return [Integer] DEBUG, INFO, WARN, ERROR or FATAL
70
+ def level
71
+ @@level
72
+ end
73
+
74
+ ##
75
+ # Return current log status.
76
+ #
77
+ # @return [Integer] DEBUG, INFO, WARN, ERROR or FATAL
78
+ def status
79
+ @@status
80
+ end
81
+
82
+ ##
83
+ # Return whether current status is DEBUG
84
+ #
85
+ # @return [Bool] true if DEBUG
86
+ def debug?
87
+ @@status == DEBUG
88
+ end
89
+
90
+ ##
91
+ # Return whether current status is INFO
92
+ #
93
+ # @return [Bool] true if INFO
94
+ def info?
95
+ @@status == INFO
96
+ end
97
+
98
+ ##
99
+ # Return whether current status is WARN
100
+ #
101
+ # @return [Bool] true if WARN
102
+ def warn?
103
+ @@status == WARN
104
+ end
105
+
106
+ ##
107
+ # Return whether current status is ERROR
108
+ #
109
+ # @return [Bool] true if ERROR
110
+ def error?
111
+ @@status == ERROR
112
+ end
113
+
114
+ ##
115
+ # Return whether current status is FATAL
116
+ #
117
+ # @return [Bool] true if FATAL
118
+ def fatal?
119
+ @@status == FATAL
120
+ end
121
+
122
+ ##
123
+ # Return string equivalent of level
124
+ #
125
+ # @param level [Integer] DEBUG, INFO, WARN, ERROR or FATAL
126
+ #
127
+ # @return [String] "DEBUG", "INFO", "WARN", "ERROR" or "FATAL"
128
+ def tag(level)
129
+ return @@tag[level] if level >= DEBUG && level <= FATAL
130
+ ""
131
+ end
132
+
133
+ ##
134
+ # Return preset OSlg message linked to status.
135
+ #
136
+ # @param status [Integer] DEBUG, INFO, WARN, ERROR or FATAL
137
+ #
138
+ # @return [String] preset OSlg message
139
+ def msg(status)
140
+ return @@msg[status] if status >= DEBUG && status <= FATAL
141
+ ""
142
+ end
143
+
144
+ ##
145
+ # Set level.
146
+ #
147
+ # @param level [Integer] DEBUG, INFO, WARN, ERROR or FATAL
148
+ #
149
+ # @return [Integer] current level
150
+ def reset(level)
151
+ @@level = level if level >= DEBUG && level <= FATAL
152
+ end
153
+
154
+ ##
155
+ # Log new entry.
156
+ #
157
+ # @param level [Integer] DEBUG, INFO, WARN, ERROR or FATAL
158
+ # @param message [String] user-provided message
159
+ #
160
+ # @return [Integer] current status
161
+ def log(level = DEBUG, message = "")
162
+ if level >= DEBUG && level <= FATAL && level >= @@level
163
+ @@logs << {level: level, message: message}
164
+ @@status = level if level > @@status
165
+ end
166
+ @@status
167
+ end
168
+
169
+ ##
170
+ # Log template 'invalid object' message and return user-set object.
171
+ #
172
+ # @param id [String] empty object identifier
173
+ # @param mth [String] calling method identifier
174
+ # @param ord [String] calling method argument order number of obj (optional)
175
+ # @param lvl [Integer] DEBUG, INFO, WARN, ERROR or FATAL (optional)
176
+ # @param res [Object] what to return (optional)
177
+ #
178
+ # @return [Object] res if specified by user
179
+ # @return [Nil] nil if return object is invalid
180
+ def invalid(id = "", mth = "", ord = 0, lvl = DEBUG, res = nil)
181
+ return nil unless defined?(res)
182
+ return res unless defined?(id ) && id
183
+ return res unless defined?(mth) && mth
184
+ return res unless defined?(ord) && ord
185
+ return res unless defined?(lvl) && lvl
186
+ mth = mth.to_s.strip
187
+ mth = mth[0...60] + " ..." if mth.length > 60
188
+ return res if mth.empty?
189
+ id = id.to_s.strip
190
+ id = id[0...60] + " ..." if id.length > 60
191
+ return res if id.empty?
192
+ msg = "Invalid '#{id}' "
193
+ msg += "arg ##{ord} " if ord.is_a?(Integer) && ord > 0
194
+ msg += "(#{mth})"
195
+ lvl = lvl.to_i unless lvl.is_a?(Integer)
196
+ log(lvl, msg) if lvl >= DEBUG && lvl <= FATAL
197
+ res
198
+ end
199
+
200
+ ##
201
+ # Log template 'instance/class mismatch' message and return user-set object.
202
+ #
203
+ # @param id [String] empty object identifier
204
+ # @param obj [Object] object to validate
205
+ # @param cl [Class] target class
206
+ # @param mth [String] calling method identifier
207
+ # @param lvl [Integer] DEBUG, INFO, WARN, ERROR or FATAL (optional)
208
+ # @param res [Object] what to return (optional)
209
+ #
210
+ # @return [Object] res if specified by user
211
+ # @return [Nil] nil if return object is invalid
212
+ def mismatch(id = "", obj = nil, cl = nil, mth = "", lvl = DEBUG, res = nil)
213
+ return nil unless defined?(res)
214
+ return res unless defined?(id ) && id
215
+ return res unless defined?(obj) && obj
216
+ return res unless defined?(cl ) && cl
217
+ return res unless defined?(mth) && mth
218
+ return res unless defined?(lvl) && lvl
219
+ mth = mth.to_s.strip
220
+ mth = mth[0...60] + " ..." if mth.length > 60
221
+ return res if mth.empty?
222
+ id = id.to_s.strip
223
+ id = id[0...60] + " ..." if id.length > 60
224
+ return res if id.empty?
225
+ return res unless cl.is_a?(Class)
226
+ return res if obj.is_a?(cl)
227
+ msg = "'#{id}' #{obj.class}? expecting #{cl} (#{mth})"
228
+ lvl = lvl.to_i unless lvl.is_a?(Integer)
229
+ log(lvl, msg) if lvl >= DEBUG && lvl <= FATAL
230
+ res
231
+ end
232
+
233
+ ##
234
+ # Log template 'missing hash key' message and return user-set object.
235
+ #
236
+ # @param id [String] empty object identifier
237
+ # @param hsh [Hash] hash to validate
238
+ # @param key [Object] target key
239
+ # @param mth [String] calling method identifier
240
+ # @param lvl [Integer] DEBUG, INFO, WARN, ERROR or FATAL (optional)
241
+ # @param res [Object] what to return (optional)
242
+ #
243
+ # @return [Object] res if specified by user
244
+ # @return [Nil] nil if not specified by user (or invalid)
245
+ def hashkey(id = "", hsh = {}, key = "", mth = "", lvl = DEBUG, res = nil)
246
+ return nil unless defined?(res)
247
+ return res unless defined?(id ) && id
248
+ return res unless defined?(hsh) && hsh
249
+ return res unless defined?(key) && key
250
+ return res unless defined?(mth) && mth
251
+ return res unless defined?(lvl) && lvl
252
+ mth = mth.to_s.strip
253
+ mth = mth[0...60] + " ..." if mth.length > 60
254
+ return res if mth.empty?
255
+ id = id.to_s.strip
256
+ id = id[0...60] + " ..." if id.length > 60
257
+ return res if id.empty?
258
+ return mismatch(id, hsh, Hash, mth, lvl, res) unless hsh.is_a?(Hash)
259
+ return res if hsh.key?(key)
260
+ msg = "'#{id}' Hash: no key '#{key}' (#{mth})"
261
+ lvl = lvl.to_i unless lvl.is_a?(Integer)
262
+ log(lvl, msg) if lvl >= DEBUG && lvl <= FATAL
263
+ res
264
+ end
265
+
266
+ ##
267
+ # Log template 'empty (uninitialized)' message and return user-set object.
268
+ #
269
+ # @param id [String] empty object identifier
270
+ # @param mth [String] calling method identifier
271
+ # @param lvl [Integer] DEBUG, INFO, WARN, ERROR or FATAL (optional)
272
+ # @param res [Object] what to return (optional)
273
+ #
274
+ # @return [Object] res if specified by user
275
+ # @return [Nil] nil if return object is invalid
276
+ def empty(id = "", mth = "", lvl = DEBUG, res = nil)
277
+ return nil unless defined?(res)
278
+ return res unless defined?(id ) && id
279
+ return res unless defined?(mth) && mth
280
+ return res unless defined?(lvl) && lvl
281
+ mth = mth.to_s.strip
282
+ mth = mth[0...60] + " ..." if mth.length > 60
283
+ return res if mth.empty?
284
+ id = id.to_s.strip
285
+ id = id[0...60] + " ..." if id.length > 60
286
+ return res if id.empty?
287
+ msg = "Empty '#{id}' (#{mth})"
288
+ lvl = lvl.to_i unless lvl.is_a?(Integer)
289
+ log(lvl, msg) if lvl >= DEBUG && lvl <= FATAL
290
+ res
291
+ end
292
+
293
+ ##
294
+ # Log template 'near zero' message and return user-set object.
295
+ #
296
+ # @param id [String] empty object identifier
297
+ # @param mth [String] calling method identifier
298
+ # @param lvl [Integer] DEBUG, INFO, WARN, ERROR or FATAL (optional)
299
+ # @param res [Object] what to return (optional)
300
+ #
301
+ # @return [Object] res if specified by user
302
+ # @return [Nil] nil if return object is invalid
303
+ def zero(id = "", mth = "", lvl = DEBUG, res = nil)
304
+ return nil unless defined?(res)
305
+ return res unless defined?(id ) && id
306
+ return res unless defined?(mth) && mth
307
+ return res unless defined?(lvl) && lvl
308
+ mth = mth.to_s.strip
309
+ mth = mth[0...60] + " ..." if mth.length > 60
310
+ return res if mth.empty?
311
+ id = id.to_s.strip
312
+ id = id[0...60] + " ..." if id.length > 60
313
+ return res if id.empty?
314
+ msg = "'#{id}' ~zero (#{mth})"
315
+ lvl = lvl.to_i unless lvl.is_a?(Integer)
316
+ log(lvl, msg) if lvl >= DEBUG && lvl <= FATAL
317
+ res
318
+ end
319
+
320
+ ##
321
+ # Log template 'negative' message and return user-set object.
322
+ #
323
+ # @param id [String] empty object identifier
324
+ # @param mth [String] calling method identifier
325
+ # @param lvl [Integer] DEBUG, INFO, WARN, ERROR or FATAL (optional)
326
+ # @param res [Object] what to return (optional)
327
+ #
328
+ # @return [Object] res if specified by user
329
+ # @return [Nil] nil if return object is invalid
330
+ def negative(id = "", mth = "", lvl = DEBUG, res = nil)
331
+ return nil unless defined?(res)
332
+ return res unless defined?(id ) && id
333
+ return res unless defined?(mth) && mth
334
+ return res unless defined?(lvl) && lvl
335
+ mth = mth.to_s.strip
336
+ mth = mth[0...60] + " ..." if mth.length > 60
337
+ return res if mth.empty?
338
+ id = id.to_s.strip
339
+ id = id[0...60] + " ..." if id.length > 60
340
+ return res if id.empty?
341
+ msg = "'#{id}' negative (#{mth})"
342
+ lvl = lvl.to_i unless lvl.is_a?(Integer)
343
+ log(lvl, msg) if lvl >= DEBUG && lvl <= FATAL
344
+ res
345
+ end
346
+
347
+ ##
348
+ # Reset log status and entries.
349
+ #
350
+ # @return [Integer] current level
351
+ def clean!
352
+ @@status = 0
353
+ @@logs = []
354
+ @@level
355
+ end
356
+
357
+ ##
358
+ # Callback when other modules extend OSlg
359
+ #
360
+ # @param base [Object] instance or class object
361
+ def self.extended(base)
362
+ base.send(:include, self)
363
+ end
364
+ end
@@ -0,0 +1,33 @@
1
+ # BSD 3-Clause License
2
+ #
3
+ # Copyright (c) 2022, Denis Bourgeois
4
+ # All rights reserved.
5
+ #
6
+ # Redistribution and use in source and binary forms, with or without
7
+ # modification, are permitted provided that the following conditions are met:
8
+ #
9
+ # 1. Redistributions of source code must retain the above copyright notice, this
10
+ # list of conditions and the following disclaimer.
11
+ #
12
+ # 2. Redistributions in binary form must reproduce the above copyright notice,
13
+ # this list of conditions and the following disclaimer in the documentation
14
+ # and/or other materials provided with the distribution.
15
+ #
16
+ # 3. Neither the name of the copyright holder nor the names of its
17
+ # contributors may be used to endorse or promote products derived from
18
+ # this software without specific prior written permission.
19
+ #
20
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24
+ # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27
+ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28
+ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
+
31
+ module OSlg
32
+ VERSION = "0.2.2".freeze
33
+ end
data/lib/oslg.rb ADDED
@@ -0,0 +1,37 @@
1
+ # BSD 3-Clause License
2
+ #
3
+ # Copyright (c) 2022, Denis Bourgeois
4
+ # All rights reserved.
5
+ #
6
+ # Redistribution and use in source and binary forms, with or without
7
+ # modification, are permitted provided that the following conditions are met:
8
+ #
9
+ # 1. Redistributions of source code must retain the above copyright notice, this
10
+ # list of conditions and the following disclaimer.
11
+ #
12
+ # 2. Redistributions in binary form must reproduce the above copyright notice,
13
+ # this list of conditions and the following disclaimer in the documentation
14
+ # and/or other materials provided with the distribution.
15
+ #
16
+ # 3. Neither the name of the copyright holder nor the names of its
17
+ # contributors may be used to endorse or promote products derived from
18
+ # this software without specific prior written permission.
19
+ #
20
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24
+ # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27
+ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28
+ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
+
31
+ begin # try to load from the gem
32
+ require "oslg/oslog"
33
+ require "oslg/version"
34
+ rescue LoadError
35
+ require_relative "oslg/oslog"
36
+ require_relative "oslg/version"
37
+ end
data/oslg.gemspec ADDED
@@ -0,0 +1,35 @@
1
+ lib = File.expand_path("lib", __dir__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require "oslg/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ # Specify which files should be added to the gem when it is released.
7
+ # "git ls-files -z" loads files in the RubyGem that have been added into git.
8
+ s.files = Dir.chdir(File.expand_path("..", __FILE__)) do
9
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
10
+ end
11
+
12
+ s.name = "oslg"
13
+ s.version = OSlg::VERSION
14
+ s.license = "BSD-3-Clause"
15
+ s.summary = "OpenStudio SDK logger"
16
+ s.description = "For SDK users who select what's logged where."
17
+ s.authors = ["Denis Bourgeois"]
18
+ s.email = ["denis@rd2.ca"]
19
+ s.platform = Gem::Platform::RUBY
20
+ s.homepage = "https://github.com/rd2/oslg"
21
+ s.bindir = "exe"
22
+ s.require_paths = ["lib"]
23
+ s.executables = s.files.grep(%r{^exe/}) { |f| File.basename(f) }
24
+ s.required_ruby_version = [">= 2.5.0", "< 2.7.3"]
25
+ s.metadata = {}
26
+
27
+ s.add_development_dependency "bundler", "~> 2.1"
28
+ s.add_development_dependency "rake", "~> 13.0"
29
+ s.add_development_dependency "rspec", "~> 3.11"
30
+ s.add_development_dependency "yard", "~> 0.9"
31
+
32
+ s.metadata["homepage_uri"] = s.homepage
33
+ s.metadata["source_code_uri"] = "#{s.homepage}/tree/v#{s.version}"
34
+ s.metadata["bug_tracker_uri"] = "#{s.homepage}/issues"
35
+ end
metadata ADDED
@@ -0,0 +1,116 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: oslg
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.2
5
+ platform: ruby
6
+ authors:
7
+ - Denis Bourgeois
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2022-07-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.1'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '13.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '13.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.11'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.11'
55
+ - !ruby/object:Gem::Dependency
56
+ name: yard
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.9'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.9'
69
+ description: For SDK users who select what's logged where.
70
+ email:
71
+ - denis@rd2.ca
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - ".github/workflows/pull_request.yml"
77
+ - ".gitignore"
78
+ - ".rspec"
79
+ - Gemfile
80
+ - LICENSE
81
+ - README.md
82
+ - Rakefile
83
+ - lib/oslg.rb
84
+ - lib/oslg/oslog.rb
85
+ - lib/oslg/version.rb
86
+ - oslg.gemspec
87
+ homepage: https://github.com/rd2/oslg
88
+ licenses:
89
+ - BSD-3-Clause
90
+ metadata:
91
+ homepage_uri: https://github.com/rd2/oslg
92
+ source_code_uri: https://github.com/rd2/oslg/tree/v0.2.2
93
+ bug_tracker_uri: https://github.com/rd2/oslg/issues
94
+ post_install_message:
95
+ rdoc_options: []
96
+ require_paths:
97
+ - lib
98
+ required_ruby_version: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: 2.5.0
103
+ - - "<"
104
+ - !ruby/object:Gem::Version
105
+ version: 2.7.3
106
+ required_rubygems_version: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ requirements: []
112
+ rubygems_version: 3.3.15
113
+ signing_key:
114
+ specification_version: 4
115
+ summary: OpenStudio SDK logger
116
+ test_files: []