Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 12 additions & 14 deletions .github/workflows/pull_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,16 @@ on:

jobs:
test_oslg:
runs-on: ubuntu-22.04
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, ubuntu-22.04]
ruby: ["2.7", "3.2"]
runs-on: ${{ matrix.os }}
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
Copy link
Member Author

@brgix brgix Aug 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No reason to keep pulling in the OpenStudio docker image.

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
- uses: actions/checkout@v4
- uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby }}
bundler-cache: true
- run: bundle exec rake
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
BSD 3-Clause License

Copyright (c) 2022-2024, Denis Bourgeois
Copyright (c) 2022-2025, Denis Bourgeois
All rights reserved.

Redistribution and use in source and binary forms, with or without
Expand Down
2 changes: 1 addition & 1 deletion lib/oslg.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# BSD 3-Clause License
#
# Copyright (c) 2022-2024, Denis Bourgeois
# Copyright (c) 2022-2025, Denis Bourgeois
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
Expand Down
68 changes: 43 additions & 25 deletions lib/oslg/oslog.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# BSD 3-Clause License
#
# Copyright (c) 2022-2024, Denis Bourgeois
# Copyright (c) 2022-2025, Denis Bourgeois
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
Expand Down Expand Up @@ -102,9 +102,9 @@ def info?
end

##
# Returns whether current status is WARN.
# Returns whether current status is WARNING.
#
# @return [Bool] whether current log status is WARN
# @return [Bool] whether current log status is WARNING
def warn?
@@status == WARN
end
Expand Down Expand Up @@ -159,19 +159,20 @@ def msg(stat)
end

##
# Converts object to String and trims if necessary.
# Converts object to String, trims if requested.
#
# @param txt [#to_s] a stringable object
# @param length [#to_i] maximum return string length
# @param len [Numeric] requested maximum string length (optional)
#
# @return [String] a trimmed message string (empty unless stringable)
def trim(txt = "", length = 60)
length = 60 unless length.respond_to?(:to_i)
length = length.to_i if length.respond_to?(:to_i)
# @return [String] a (trimmed) string (empty unless stringable)
def trim(txt = "", len = nil)
return "" unless txt.respond_to?(:to_s)

txt = txt.to_s.strip
txt = txt[0...length] + " ..." if txt.length > length

if len.is_a?(Numeric)
txt = txt[0...len.to_i] + " ..." if txt.length > len.to_i
end
Copy link
Member Author

@brgix brgix Aug 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Revisiting this proposed change, having tested it with other gems (i.e. OSlg as a dependency). OSlg shall no longer have a built-in limit on log message lengths. Good option to offer, but not one to bake in.

All OSlg log functions (e.g. zero, mismatch) call on log, which itself calls trim:

  • ensures valid log message strings
  • trims final log message length if requested by user
  • if trimming not requested by user, leaves log message as is

Each OSlg log function now has an additional len parameter, which is nilled by default (and therefore ignored). Users are free to set len to e.g. "160" chars.


txt
end
Expand All @@ -193,21 +194,28 @@ def reset(lvl = DEBUG)
end

##
# Logs a new entry, if provided arguments are valid.
# Logs a new entry. Overall log status is raised if new level is greater
# than current level (e.g. FATAL > ERROR). Candidate log entry is ignored and
# status remains unchanged if the new level cannot be converted to an integer,
# if not an OSlg constant (once converted), or if new level is below the
# current log level. Relies on OSlg method 'trim()': candidate log message is
# ignored and status unchanged if message is not a valid string.
#
# @param lvl [#to_i] DEBUG, INFO, WARN, ERROR or FATAL
# @param message [#to_s] user-provided log message
# @param len [Numeric] maximum log message length (optional)
#
# @example A user warning
# log(WARN, "Surface area < 100cm2")
#
# @return [DEBUG, INFO, WARN, ERROR, FATAL] updated/current status
def log(lvl = DEBUG, message = "")
def log(lvl = DEBUG, message = "", len = nil)
return @@status unless lvl.respond_to?(:to_i)
return @@status unless message.respond_to?(:to_s)

lvl = lvl.to_i
message = message.to_s
message = trim(message, len)
return @@status if message.empty?
return @@status if lvl < DEBUG
return @@status if lvl > FATAL
return @@status if lvl < @@level
Expand All @@ -220,19 +228,24 @@ def log(lvl = DEBUG, message = "")

##
# Logs template 'invalid object' message, if provided arguments are valid.
# Relies on OSlg method 'log()': first check out its own operation, exit
# conditions and module side effects. Candidate log entry is ignored and
# status remains unchanged if 'ord' cannot be converted to an integer.
# Argument 'ord' is ignored unless > 0.
#
# @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 (optional)
# @param res what to return (optional)
# @param len [Numeric] maximum log message length (optional)
#
# @example An invalid argument, logging a FATAL error, returning FALSE
# return invalid("area", "sum", 0, FATAL, false) if area > 1000000
#
# @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)
def invalid(id = "", mth = "", ord = 0, lvl = DEBUG, res = nil, len = nil)
return res unless id.respond_to?(:to_s)
return res unless mth.respond_to?(:to_s)
return res unless ord.respond_to?(:to_i)
Expand All @@ -250,7 +263,7 @@ def invalid(id = "", mth = "", ord = 0, lvl = DEBUG, res = nil)
msg = "Invalid '#{id}' "
msg += "arg ##{ord} " if ord > 0
msg += "(#{mth})"
log(lvl, msg)
log(lvl, msg, len)

res
end
Expand All @@ -266,13 +279,14 @@ def invalid(id = "", mth = "", ord = 0, lvl = DEBUG, res = nil)
# @param mth [#to_s] calling method identifier (optional)
# @param lvl [#to_i] DEBUG, INFO, WARN, ERROR or FATAL (optional)
# @param res what to return (optional)
# @param len [Numeric] maximum log message length (optional)
#
# @example A mismatched argument instance/class
# mismatch("area", area, Float, "sum") unless area.is_a?(Numeric)
#
# @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)
def mismatch(id = "", obj = nil, cl = nil, mth = "", lvl = DEBUG, res = nil, len = nil)
return res unless id.respond_to?(:to_s)
return res unless mth.respond_to?(:to_s)
return res unless cl.is_a?(Class)
Expand All @@ -287,7 +301,7 @@ def mismatch(id = "", obj = nil, cl = nil, mth = "", lvl = DEBUG, res = nil)
return res if lvl < DEBUG
return res if lvl > FATAL

log(lvl, "'#{id}' #{obj.class}? expecting #{cl} (#{mth})")
log(lvl, "'#{id}' #{obj.class}? expecting #{cl} (#{mth})", len)

res
end
Expand All @@ -302,13 +316,14 @@ def mismatch(id = "", obj = nil, cl = nil, mth = "", lvl = DEBUG, res = nil)
# @param mth [#to_s] calling method identifier
# @param lvl [#to_i] DEBUG, INFO, WARN, ERROR or FATAL (optional)
# @param res what to return (optional)
# @param len [Numeric] maximum log message length (optional)
#
# @example A missing Hash key
# hashkey("floor area", floor, :area, "sum") unless floor.key?(:area)
#
# @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)
def hashkey(id = "", hsh = {}, key = "", mth = "", lvl = DEBUG, res = nil, len = nil)
return res unless id.respond_to?(:to_s)
return res unless hsh.is_a?(Hash)
return res if hsh.key?(key)
Expand All @@ -323,7 +338,7 @@ def hashkey(id = "", hsh = {}, key = "", mth = "", lvl = DEBUG, res = nil)
return res if lvl < DEBUG
return res if lvl > FATAL

log(lvl, "Missing '#{key}' key in '#{id}' Hash (#{mth})")
log(lvl, "Missing '#{key}' key in '#{id}' Hash (#{mth})", len)

res
end
Expand All @@ -335,13 +350,14 @@ def hashkey(id = "", hsh = {}, key = "", mth = "", lvl = DEBUG, res = nil)
# @param mth [#to_s] calling method identifier
# @param lvl [#to_i] DEBUG, INFO, WARN, ERROR or FATAL (optional)
# @param res what to return (optional)
# @param len [Numeric] maximum log message length (optional)
#
# @example An uninitialized variable, logging an ERROR, returning FALSE
# empty("zone", "conditioned?", FATAL, false) if space.thermalZone.empty?
#
# @return user-provided object
# @return [nil] if user hasn't provided an object to return
def empty(id = "", mth = "", lvl = DEBUG, res = nil)
def empty(id = "", mth = "", lvl = DEBUG, res = nil, len = nil)
return res unless id.respond_to?(:to_s)
return res unless mth.respond_to?(:to_s)
return res unless lvl.respond_to?(:to_i)
Expand All @@ -354,7 +370,7 @@ def empty(id = "", mth = "", lvl = DEBUG, res = nil)
return res if lvl < DEBUG
return res if lvl > FATAL

log(lvl, "Empty '#{id}' (#{mth})")
log(lvl, "Empty '#{id}' (#{mth})", len)

res
end
Expand All @@ -366,13 +382,14 @@ def empty(id = "", mth = "", lvl = DEBUG, res = nil)
# @param mth [#to_s] calling method identifier
# @param lvl [#to_i] DEBUG, INFO, WARN, ERROR or FATAL (optional)
# @param res what to return (optional)
# @param len [Numeric] maximum log message length (optional)
#
# @example A near-zero variable
# zero("floor area", "sum") if floor[:area].abs < TOL
#
# @return user-provided object
# @return [nil] if user hasn't provided an object to return
def zero(id = "", mth = "", lvl = DEBUG, res = nil)
def zero(id = "", mth = "", lvl = DEBUG, res = nil, len = nil)
return res unless id.respond_to?(:to_s)
return res unless mth.respond_to?(:to_s)
return res unless lvl.respond_to?(:to_i)
Expand All @@ -386,7 +403,7 @@ def zero(id = "", mth = "", lvl = DEBUG, res = nil)
return res if lvl < DEBUG
return res if lvl > FATAL

log(lvl, "Zero '#{id}' (#{mth})")
log(lvl, "Zero '#{id}' (#{mth})", len)

res
end
Expand All @@ -398,13 +415,14 @@ def zero(id = "", mth = "", lvl = DEBUG, res = nil)
# @param mth [String] calling method identifier
# @param lvl [Integer] DEBUG, INFO, WARN, ERROR or FATAL (optional)
# @param res [Object] what to return (optional)
# @param len [Numeric] maximum log message length (optional)
#
# @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)
def negative(id = "", mth = "", lvl = DEBUG, res = nil, len = nil)
return res unless id.respond_to?(:to_s)
return res unless mth.respond_to?(:to_s)
return res unless lvl.respond_to?(:to_i)
Expand All @@ -417,7 +435,7 @@ def negative(id = "", mth = "", lvl = DEBUG, res = nil)
return res if lvl < DEBUG
return res if lvl > FATAL

log(lvl, "Negative '#{id}' (#{mth})")
log(lvl, "Negative '#{id}' (#{mth})", len)

res
end
Expand Down
4 changes: 2 additions & 2 deletions lib/oslg/version.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# BSD 3-Clause License
#
# Copyright (c) 2022-2024, Denis Bourgeois
# Copyright (c) 2022-2025, Denis Bourgeois
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
Expand Down Expand Up @@ -29,5 +29,5 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

module OSlg
VERSION = "0.3.0".freeze # OSlg version
VERSION = "0.4.0".freeze # OSlg version
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although branch is "v033", bumping up version to v.0.4.0 given API changes.

end
17 changes: 11 additions & 6 deletions spec/oslg_tests_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -86,20 +86,25 @@
expect(cls2.mismatch("x", "String", String, "foo")).to be_nil
expect(cls2.logs).to be_empty

# Longish error message, exceeding 160 chars.
array = (1..60).to_a
l1 = 3 * 9 # "1, " + "2, " + "3, " ...+ "9, "
l2 = 4 * (59 - 9) # "10, " + "11, " + 12, ...+ "59, "
l3 = 2 # "60"
l4 = 2 # "[]"
expect(l1 + l2 + l3 + l4).to eq(231)
expect(array.to_s.size).to eq(l1 + l2 + l3 + l4)
expect(cls2.mismatch("x", "String", Array, array)).to be_nil
expect(cls2.mismatch("x", "String", Array, array, cls2::FATAL, nil, 160)).to be_nil
Copy link
Member Author

@brgix brgix Aug 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To request a shortened logged message, users must activate the last log function parameter, len (here, "160").


Tested, works, hopefully done. Certainly not keen on revisiting this in the future (unless absolutely necessary, e.g. bug, future Ruby change). So definitely trying to nail this down ASAP.

Running larger test suites (e.g. parent gems, calling upon OSlg). Will only merge and re-release OSlg once all other test suites pass.

expect(cls2.logs.size).to eq(1)
expect(cls2.logs.first).to have_key(:message)
str1 = "'x' String? expecting Array " # 28 chars
str2 = "([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, ...)"
expect(str1.size + str2.size).to eq(28 + 60 + "(".length + " ...)".length)
expect(cls2.logs.first[:message].length).to eq(str1.size + str2.size)
expect(cls2.logs.first[:message]).to eq(str1 + str2)
str1 = "'x' String? expecting Array " # 28 chars
str2 = "([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, " # 45 chars
str3 = "14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, " # 44 chars
str4 = "25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, ..." # 47 chars
str0 = str1 + str2 + str3 + str4
expect(str0.length).to eq(164) # i.e. 160 MAX + " ..."
expect(cls2.logs.first[:message].length).to eq(str0.length)
expect(cls2.logs.first[:message]).to eq(str0)

expect(cls2.clean!).to eq(cls2::DEBUG)
expect(cls2.hashkey("x", {bar: 0}, "k", "foo")).to be_nil
Expand Down