tina4ruby 3.13.2 → 3.13.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a9136344be97c23d23b85f26a14f5a992cf7df49c16ff6d8a60c928461ab222b
4
- data.tar.gz: ea8eb37ac2e183ff58551b4e513e37359075dd1aab8672ea16a02d99acae9980
3
+ metadata.gz: 6806b64505d23caba2d53a7b08b1411aa1e0ca924ea883d660dedae1c81f5766
4
+ data.tar.gz: e168b0a72f99e8cab66c1532a0909d480e10e330c65104749ec8dafb4e26837d
5
5
  SHA512:
6
- metadata.gz: 1317a3d0298906f4470f46cb86288b1b0573364028b7d15244aa04447b69509132c7f443924368c75bb1461b146ff93ca5d0d8a418fa29825eb120221c72e135
7
- data.tar.gz: fadb37d5d3a570212a75eb5f683fbf78bfe4af0e78128d96fb293c355c66631bd3bfad570a3d320e47c30da2209ec01ebacfe2be26edc1dc2c7dec13a819c0d0
6
+ metadata.gz: fd1d7d614b01886cb2e70ffcd04503ce3155073350f70dc92e6414816c5993a39b63b91965f49c30ea3275a6c72b62eea510ba64db74db0384ad925d7bdb0b76
7
+ data.tar.gz: 745992728883c28e11d3716977a9bb9e5f58d4a043b7aa285c6dc8113b8c95d3ffef10ac7b52aa339ef0172c308687f6c3004926af1daf1f4a3737601c008994
data/lib/tina4/env.rb CHANGED
@@ -83,6 +83,14 @@ module Tina4
83
83
  "TINA4_SECRET" => "tina4-secret-change-me"
84
84
  }.freeze
85
85
 
86
+ # Typed env-var coercion — parity with tina4_python's Env class,
87
+ # tina4-php's Tina4\Env, and tina4-nodejs's Env. Truthy values
88
+ # (case-insensitive after strip): "1", "true", "on", "yes", "y", "t".
89
+ # Falsy: "0", "false", "off", "no", "n", "f", empty string. Anything
90
+ # else falls through to default.
91
+ TRUTHY = %w[1 true on yes y t].freeze
92
+ FALSY = %w[0 false off no n f].freeze
93
+
86
94
  # Check if a value is truthy for env boolean checks.
87
95
  #
88
96
  # Accepts: "true", "True", "TRUE", "1", "yes", "Yes", "YES", "on", "On", "ON".
@@ -91,6 +99,58 @@ module Tina4
91
99
  %w[true 1 yes on].include?(val.to_s.strip.downcase)
92
100
  end
93
101
 
102
+ # Read an env var and coerce to Boolean. Returns +default+ when the
103
+ # var is unset or holds a value outside the TRUTHY/FALSY tables.
104
+ # Never raises — bad input falls through to default.
105
+ def self.bool(name, default: false)
106
+ raw = ENV[name.to_s]
107
+ return default if raw.nil?
108
+ token = raw.strip.downcase
109
+ return true if TRUTHY.include?(token)
110
+ return false if FALSY.include?(token) || token.empty?
111
+ default
112
+ end
113
+
114
+ # Read an env var and coerce to Integer. Logs a warning via Tina4::Log
115
+ # (if loaded) and returns +default+ on parse failure. Never raises.
116
+ def self.int(name, default: 0)
117
+ raw = ENV[name.to_s]
118
+ return default if raw.nil?
119
+ Integer(raw.strip)
120
+ rescue ArgumentError, TypeError
121
+ log_warning("Env.int(#{name.inspect}): could not parse #{raw.inspect} as Integer — using default #{default.inspect}")
122
+ default
123
+ end
124
+
125
+ # Read an env var and coerce to Float. Logs a warning via Tina4::Log
126
+ # (if loaded) and returns +default+ on parse failure. Never raises.
127
+ def self.float(name, default: 0.0)
128
+ raw = ENV[name.to_s]
129
+ return default if raw.nil?
130
+ Float(raw.strip)
131
+ rescue ArgumentError, TypeError
132
+ log_warning("Env.float(#{name.inspect}): could not parse #{raw.inspect} as Float — using default #{default.inspect}")
133
+ default
134
+ end
135
+
136
+ # Read an env var as a String. Returns +default+ when unset.
137
+ # Whitespace is preserved — this is a pass-through for the raw env value,
138
+ # matching Python's Env.str semantics.
139
+ def self.str(name, default: "")
140
+ raw = ENV[name.to_s]
141
+ return default if raw.nil?
142
+ raw
143
+ end
144
+
145
+ # Emit a warning via Tina4::Log without creating a load-order dependency.
146
+ # Mirrors Python's Env._log_warning: silently skip if Log isn't loaded.
147
+ def self.log_warning(message)
148
+ Tina4::Log.warning(message) if defined?(Tina4::Log)
149
+ rescue NameError, StandardError
150
+ # Log not wired up yet (very early bootstrap) — swallow.
151
+ end
152
+ private_class_method :log_warning
153
+
94
154
  class << self
95
155
  def load_env(root_dir = Dir.pwd)
96
156
  env_file = resolve_env_file(root_dir)
data/lib/tina4/log.rb CHANGED
@@ -203,8 +203,10 @@ module Tina4
203
203
  ts = utc_timestamp
204
204
  rid = get_request_id
205
205
  rid_str = rid ? " [#{rid}]" : ""
206
+ fn = caller_name
207
+ fn_str = fn ? " [#{fn}]" : ""
206
208
  ctx = @current_context && !@current_context.empty? ? " #{JSON.generate(@current_context)}" : ""
207
- "#{ts} [#{level_str.ljust(7)}]#{rid_str} #{message}#{ctx}"
209
+ "#{ts} [#{level_str.ljust(7)}]#{rid_str}#{fn_str} #{message}#{ctx}"
208
210
  end
209
211
 
210
212
  def json_line(level, message)
@@ -216,10 +218,46 @@ module Tina4
216
218
  }
217
219
  rid = get_request_id
218
220
  entry[:request_id] = rid if rid
221
+ fn = caller_name
222
+ entry[:function] = fn if fn
219
223
  entry[:context] = @current_context if @current_context && !@current_context.empty?
220
224
  JSON.generate(entry)
221
225
  end
222
226
 
227
+ # Names that belong to Log itself — walk past them so the reported
228
+ # frame is the real caller (e.g. the route handler or service
229
+ # method that called Log.info). Kept as a Set for O(1) lookup.
230
+ OWN_FRAMES = %w[
231
+ caller_name format_line json_line log colorize write_to_file
232
+ debug info warning error critical
233
+ ].freeze
234
+
235
+ # Names that are noise — Ruby block labels, lambdas, top-level
236
+ # script frames. We skip these the same way Python skips <module>
237
+ # and <lambda>.
238
+ NOISE_FRAME_RE = /\A(?:block(?: \(\d+ levels\))? in |<top \(required\)>|<main>)/
239
+
240
+ # Return the name of the function that called Log.{debug,info,warning,error}.
241
+ # Active only when TINA4_LOG_FUNC=true (parity feature #41).
242
+ # Returns nil on any error so it never crashes a log call.
243
+ def caller_name
244
+ return nil unless Tina4::Env.bool("TINA4_LOG_FUNC")
245
+
246
+ # caller_locations(2, 16) skips this method + log() and gives us
247
+ # up to 16 frames to walk. We bail out the moment we hit a frame
248
+ # whose base_label isn't in OWN_FRAMES and isn't a block label.
249
+ locs = caller_locations(2, 16) || []
250
+ locs.each do |loc|
251
+ label = loc.base_label.to_s
252
+ next if OWN_FRAMES.include?(label)
253
+ next if label.empty? || NOISE_FRAME_RE.match?(label)
254
+ return label
255
+ end
256
+ nil
257
+ rescue StandardError
258
+ nil
259
+ end
260
+
223
261
  def colorize(level, line)
224
262
  color = case level
225
263
  when :debug then COLORS[:cyan]
data/lib/tina4/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Tina4
4
- VERSION = "3.13.2"
4
+ VERSION = "3.13.3"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tina4ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.13.2
4
+ version: 3.13.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tina4 Team