loba 2.0.0 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fd37694b2e7fc3a573237e959410b0bb388e4b4873f16ebb75724c8b3c2db359
4
- data.tar.gz: c26f5ea9b333bf0bef43d19f0cd139aebe88420eb800daa344b363361fc05a05
3
+ metadata.gz: 6d53014bd42826b2fee7d16d06ce19a345522ecfd3eb105b5b286f1bd5348e13
4
+ data.tar.gz: 2d6258dd046d5899469ebdba37606cc4da74b35ae027e87151d237bf83050137
5
5
  SHA512:
6
- metadata.gz: 5529034ea281db641c3105b0aba812de2b7d05933816f690a9f3cade786b9a6b7c42004ce5567ec767902538f817a17fb976c8a0f20e72ce9842f8ef53b7c4d3
7
- data.tar.gz: cfcff516d957181281939ed46af92027d2c673dd6b9035a421fda4c04118c8e7d47300727cbab8230b6fef93e8ec23c368f689244e843bb87dccf20e85791b85
6
+ metadata.gz: 9c109e14fdbf2d6a6271e92f640cf11a214d92e434938509e8f2ad015a2c6286798b22c1cced8defce4f588394e078e098cc4fa4ef3db5ea07f6a3f21f58141c
7
+ data.tar.gz: 797fef5afe7e868135070abbd950c6981cdcb63720d0891aa377d62f3086b885c0dfdf9d62a5776ef0034e1ad591f4e05c7b042c73392ce2c85f18a6c8bb4d0f
data/CHANGELOG.md CHANGED
@@ -7,6 +7,18 @@ and, as of version 0.3.0 and later, this project adheres to [Semantic Versioning
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [2.1.0] - 2024-09-09
11
+ ### Added
12
+ - Added `logger` option for accepting a logger to write to instead of default behavior
13
+ - Added `logdev` option to direct logging in non-Rails environments
14
+ - Added `out` option to allow turning off console (`puts`) output
15
+
16
+ ### Changed
17
+ - Changed so `log` option will allow logging in non-Rails environments
18
+ - Changed so `log` option will be defaulted to `true` when `out` options is set to `false`
19
+ - Updated documentation for new and changed options and to improve completeness
20
+ - Refreshed gems and dependencies
21
+
10
22
  ## [2.0.0] - 2023-07-07
11
23
  ### Added
12
24
  - `Loba.ts`: `log` option to allow logging to Rails.logger (ignored if unavailable)
@@ -15,7 +27,7 @@ and, as of version 0.3.0 and later, this project adheres to [Semantic Versioning
15
27
 
16
28
  ### Changed
17
29
  - Dropped support for Ruby prior to 3.0.6
18
- - Changed output to always write to STDOUT (regardless whether Rails is present)
30
+ - Changed output to always write to `$stdout` (regardless whether Rails is present)
19
31
  - Changed to only write to Rails.logger (when present) when `log` option is set to `true`
20
32
  - Updated YARD documentation for improved completeness
21
33
  - Refreshed gems and dependencies
@@ -92,7 +104,8 @@ and, as of version 0.3.0 and later, this project adheres to [Semantic Versioning
92
104
  ### Added
93
105
  - Initial implementation
94
106
 
95
- [Unreleased]: https://github.com/rdnewman/loba/compare/v2.0.0...HEAD
107
+ [Unreleased]: https://github.com/rdnewman/loba/compare/v2.1.0...HEAD
108
+ [2.1.0]: https://github.com/rdnewman/loba/compare/v2.0.0...v2.1.0
96
109
  [2.0.0]: https://github.com/rdnewman/loba/compare/v1.2.1...v2.0.0
97
110
  [1.2.1]: https://github.com/rdnewman/loba/compare/v1.2.0...v1.2.1
98
111
  [1.2.0]: https://github.com/rdnewman/loba/compare/v1.1.0...v1.2.0
data/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2015-2021 Richard Newman
3
+ Copyright (c) 2015-2023 Richard Newman
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -7,7 +7,7 @@
7
7
 
8
8
  ![Loba is "write" in Zulu](readme/zulu.png)
9
9
 
10
- Easy tracing for debugging: handy methods for adding trace lines to output or Rails logs.
10
+ Easy tracing for debugging: handy methods for adding trace lines to output (or logs).
11
11
 
12
12
  (Installation is pretty much what you'd expect for a gem, but read Environment Notes below first.)
13
13
 
@@ -20,19 +20,19 @@ There are two kinds of questions I usually want to answer when trying to diagnos
20
20
 
21
21
  Loba statements are intended to be terse to minimize typing.
22
22
 
23
- Loba statements are intended to be minimally invasive and atomic. They should not have any (much) more impact than regular `puts` or `Rails.logger.debug` statements.
23
+ Loba statements are intended to be minimally invasive and atomic. They should have negligible impact over regular `puts` or logging statements.
24
24
 
25
25
  Loba statements are expected to be removed when you're done with them. No point in cluttering up production code.
26
26
 
27
- Loba will always write to STDOUT (i.e., `puts`).
27
+ Loba will generally always write to `$stdout` (i.e., `puts`). In addition to `$stdout`, Loba can also be made to write to a log (:debug). Writing to `$stdout` can be overridden.
28
28
 
29
- Loba will work equally well with or without Rails. If Rails is present, in addition to STDOUT, Loba will also always write to `Rails.logger.debug`.
29
+ Loba will work equally well with or without Rails. If Rails is present and writing to a log is wanted, it will use the Rails log (e.g., `Rails.logger.debug`).
30
30
 
31
31
  Loba uses the [rainbow gem](https://rubygems.org/gems/rainbow) to help make trace statements more visible.
32
32
 
33
33
  ## Usage
34
34
 
35
- My advice is to align Loba statements to the far left in your source code (a la `=begin` or `=end`) so they're easy to see and remove when you're done.
35
+ Aligning Loba statements to the far left in your source code (a la `=begin` or `=end`) will make them easier to see and remove when you're done. You may though find this somewhat annoying to do if your editor auto-indents.
36
36
 
37
37
  #### Timestamp notices: `Loba.ts`
38
38
 
@@ -56,7 +56,7 @@ You can read [more detail](readme/ts.md) on this command.
56
56
 
57
57
  #### Variable or method return inspection: `Loba.val`
58
58
 
59
- Inserts line to Rails.logger.debug (or to STDOUT if Rails.logger not available) showing value with method and class identification
59
+ Writes line to `$stdout` (or optionally to a log, `logger.debug`) showing value with method and class identification.
60
60
 
61
61
  ```ruby
62
62
  Loba.val :var_sym # the :var_sym argument is the variable or method name given as a symbol
@@ -70,6 +70,16 @@ For example,
70
70
 
71
71
  You can read [more detail](readme/val.md) on this command.
72
72
 
73
+ #### Output and logging options
74
+
75
+ There are several options to control where Loba writes its output:
76
+ * `out`: controls whether `puts` to `$stdout` occurs (default: `true`)
77
+ * `log`: controls whether logging occurs (default: `false`)
78
+ * `logger`: controls which logger is used
79
+ * `logdev`: in non-Rails environments, another way to direct where logging occurs
80
+
81
+ You can read [more detail](readme/log.md) about how to use these options.
82
+
73
83
  #### Snippet example
74
84
 
75
85
  ```ruby
@@ -107,14 +117,14 @@ The expectation is that Loba statements are just for development or test trace s
107
117
 
108
118
  `Loba.ts` and `Loba.val` try to protect against timestamp or value notice requests being accidentally left in the code by checking for the Rails environment Loba is being invoked under. If in production, `Loba.ts` and `Loba.val` will normally just return immediately without attempting to render anything to help minimize any impact on production code.
109
119
 
110
- However, that behavior can be overridden by using the options hash with `:production => true` as an additional last argument to output a notice even when in the production environment. Note also behavior of the `log` option which defaults to `false` (introduced in v2.0.0). In general, enabling in production should be avoided. We're consenting adults.
120
+ However, that behavior can be overridden by using the option `production: true` as an additional argument to output a notice even when in the production environment. Note also behavior of the `log` option, which defaults to `false` (introduced in v2.0.0). In general, enabling in production should not be done, but we're consenting adults.
111
121
 
112
- WARNING: this gem depends on the [binding_of_caller gem](https://rubygems.org/gems/binding_of_caller) -- use `:production => true` with their warning in mind:
122
+ WARNING: this gem depends on the [binding_of_caller gem](https://rubygems.org/gems/binding_of_caller) -- use `production: true` with their warning in mind:
113
123
  > **Recommended for use only in debugging situations. Do not use this in production apps.**
114
124
 
115
- These considerations also have an impact on how you install the Loba gem when using `bundler`. If you only install the gem for :development and :test, then any Loba statements left in the code when it goes to production will cause an error because the statements wouldn't be recognized. That's usually a Good Thing, if you never want them left in.
125
+ These considerations also have an impact on how you install the Loba gem when using `bundler`. If you only install the gem for `:development` and `:test`, then any Loba statements left in the code when it goes to production will cause an error because the statements wouldn't be recognized. That can be a good thing if you never want them left in.
116
126
 
117
- If you simply install the gem for all environments, then Loba will be available in production, but you may not notice as easily if some Loba calls are unintentionally left in. Of course, if you want those statements to work in production, then you should install the gem for all environments.
127
+ If you simply install the gem for all environments, then Loba will be available in production, but you may not notice as easily if some Loba calls are unintentionally left in. Of course, if you want Loba statements to possibly work in production, then you should install the gem for all environments.
118
128
 
119
129
  The following is the code example snippet but always logging even in Rails production environments:
120
130
 
@@ -122,12 +132,12 @@ The following is the code example snippet but always logging even in Rails produ
122
132
  class HelloWorld
123
133
  def initialize
124
134
  @x = 42
125
- Loba.ts production: true
135
+ Loba.ts log: true, production: true
126
136
  @y = "Charlie"
127
137
  end
128
138
 
129
139
  def hello
130
- Loba.val :@x, production: true
140
+ Loba.val :@x, log: true, production: true
131
141
  puts "Hello, #{@y}" if @x == 42
132
142
  Loba.ts true
133
143
  end
@@ -162,7 +172,7 @@ gem 'loba', require: false
162
172
  And then execute:
163
173
 
164
174
  ```bash
165
- bundle
175
+ bundle install
166
176
  ```
167
177
 
168
178
  ## Development
data/SECURITY.md CHANGED
@@ -11,7 +11,8 @@ additional information.
11
11
 
12
12
  | Version | Supported |
13
13
  | ------- | ------------------ |
14
- | 2.x.x | :white_check_mark: |
14
+ | 2.1.x | :white_check_mark: |
15
+ | 2.0.x | :white_check_mark: |
15
16
  | < 2.0 | :x: |
16
17
 
17
18
  ## Reporting a Vulnerability
data/lib/loba/error.rb ADDED
@@ -0,0 +1,18 @@
1
+ module Loba
2
+ # Errors raised by Loba are subclasses of +Loba::Error+.
3
+ # Rescue this class to rescue any Loba-specific errors.
4
+ # @api private
5
+ class Error < StandardError; end
6
+
7
+ # Error raised with an invalid logdev is specified
8
+ # @api private
9
+ class InvalidLogdevOptionError < Error; end
10
+
11
+ # Error raised with an invalid logger is specified
12
+ # @api private
13
+ class InvalidLoggerOptionError < Error; end
14
+
15
+ # Error raised with an invalid target for #puts is specified
16
+ # @api private
17
+ class InvalidOutOptionError < Error; end
18
+ end
@@ -0,0 +1,43 @@
1
+ require 'logger'
2
+ require 'English'
3
+
4
+ module Loba
5
+ module Internal
6
+ module Platform
7
+ # Custom logging formatter (for when Rails is not involved)
8
+ class Formatter
9
+ # Formats supplied message to write to logger.
10
+ #
11
+ # This formatter ignores +severity+, +time+, and +progname+ because it enforces
12
+ # that Loba messages are written out to the log without additional ornamentation.
13
+ #
14
+ # @param message [String] Loba content to write out
15
+ # @return [String] message formatted for writing to log
16
+ def call(_severity, _time, _progname, message)
17
+ "#{format(message)}#{$INPUT_RECORD_SEPARATOR}"
18
+ end
19
+
20
+ private
21
+
22
+ def format(message)
23
+ case message
24
+ when ::String
25
+ message
26
+ when ::Exception
27
+ format_exception(message)
28
+ else
29
+ message.inspect
30
+ end
31
+ end
32
+
33
+ def format_exception(err)
34
+ backtrace = err.backtrace
35
+ result = "#{err.message} (#{err.class})"
36
+ return result if backtrace.to_s.empty?
37
+
38
+ result + "\n#{backtrace}"
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,22 @@
1
+ module Loba
2
+ module Internal
3
+ module Platform
4
+ # Internal module for considering Rails
5
+ module WithinRails
6
+ # Determines if Rails has its logger defined (generally +true+)
7
+ # @return [boolean] +true+ if +Rails.logger+ is defined
8
+ def logger?
9
+ Internal.boolean_cast(defined?(Rails)) && Internal.boolean_cast(Rails.logger)
10
+ end
11
+ module_function :logger?
12
+
13
+ # Determines if Rails is running in a production environment
14
+ # @return [boolean] +true+ if +Rails.env+ is +:production+
15
+ def production?
16
+ Internal.boolean_cast(defined?(Rails)) && Rails.env.production?
17
+ end
18
+ module_function :production?
19
+ end
20
+ end
21
+ end
22
+ end
@@ -1,44 +1,25 @@
1
+ require_relative 'platform/formatter'
2
+ require_relative 'platform/within_rails'
3
+
1
4
  module Loba
2
5
  module Internal
3
- # Internal class for managing logging across Rails and non-Rails applications
4
- class Platform
6
+ # Internal module for managing output and logging across Rails and non-Rails applications
7
+ module Platform
5
8
  class << self
6
- # Checks if Rails is present
7
- # @return [Boolean] true if Rails appears to be available; otherwise, false
8
- def rails?
9
- defined?(Rails) ? true : false
10
- end
11
-
12
- # Checks if logging output is permitted.
13
- # @return [Boolean] true if logging is to be allowed; otherwise, false
14
- def logging_ok?(force_true = false)
15
- return true if force_true
16
- return true unless rails?
17
-
18
- begin
19
- !Rails.env.production?
20
- rescue StandardError
21
- true # let it attempt to log anyway
22
- end
23
- end
24
-
25
- # Provides logging mechanism appropriate in the application.
9
+ # Provides mechanism for appropriate console output and logging.
10
+ #
11
+ # @note To avoid doubled output, if a non-Rails logger is to be logged to and +logdev+ is
12
+ # set to +$stdout+, then output will be suppressed (i.e., +settings.out+ is +false+).
13
+ # Doubled output can still occur; in that case, explicitly use +out: false+.
26
14
  #
27
- # Returned lambda takes 2 arguments:
28
- # * arg [String] value to be output (and potentially logged)
29
- # * force_log [Boolean] when false (default), never logs to Rails.logger;
30
- # when true, logs to Rails.logger if present
31
- # @return [Lambda] procedure for logging output
32
- def logger
33
- if rails? && Rails.logger.present?
34
- lambda do |arg, force_log = false|
35
- puts arg
36
- return unless force_log
15
+ # @param settings [::Loba::Internal::Settings] settings for output control
16
+ # @return [lambda {|message| ...}] procedure for presenting output. Takes one argument,
17
+ # +message+ (String), for the output to be written
18
+ def writer(settings:)
19
+ lambda do |message|
20
+ puts(message) if settings.out?
37
21
 
38
- Rails.logger.debug arg
39
- end
40
- else
41
- ->(arg, _force_log = false) { puts arg }
22
+ settings.logger.debug { message } if settings.log?
42
23
  end
43
24
  end
44
25
  end
@@ -0,0 +1,143 @@
1
+ module Loba
2
+ module Internal
3
+ # Internal class for tracking output and logging settings based on supplied options
4
+ class Settings
5
+ # @return [boolean] whether logging is performed
6
+ attr_reader :log
7
+ alias log? log
8
+
9
+ # @return [Logger] +::Logger+ used for logging; may be +nil+ if not logging
10
+ attr_reader :logger
11
+
12
+ # @return [nil, String, IO, File::NULL]
13
+ # any custom (overridden) logging device being written to; +nil+ if none specified
14
+ attr_reader :logdev
15
+
16
+ # @return [boolean] +false+ if console output is suppressed; otherwise, +true+
17
+ attr_reader :out
18
+ alias out? out
19
+
20
+ # @return [boolean]
21
+ # +true+ if Loba is enabled even within a Rails production environment; otherwise, +false+
22
+ attr_reader :production
23
+ alias production? production
24
+
25
+ # @param log [boolean]
26
+ # set to +false+ if no logging is ever wanted
27
+ # (default when not in Rails and +logger+ is nil);
28
+ # set to +true+ if logging is always wanted (default when in Rails or
29
+ # when +logger+ is set or +out+ is false);
30
+ # @param logger [Logger] override logging with specified Ruby Logger
31
+ # @param logdev [nil, String, IO, File::NULL]
32
+ # custom log device to use (when not in Rails); ignored if +logger+ is set;
33
+ # must be filename or IO object
34
+ # @param out [boolean]
35
+ # set to +false+ if console output is to be suppressed
36
+ # @param production [boolean]
37
+ # set to +true+ if Loba is to work even within a Rails production environment
38
+ # @note To avoid doubled output, if a non-Rails logger is to be logged to and +logdev+ is
39
+ # set to +$stdout+, then output will be suppressed (i.e., +settings.out+ is +false+).
40
+ # Doubled output can still occur; in that case, explicitly use +out: false+.
41
+ # @raise [InvalidLoggerOptionError] when an invalid logger is specified
42
+ # @raise [InvalidLogdevOptionError] when an invalid logdev is specified
43
+ def initialize(log: nil, logger: nil, logdev: nil, out: true, production: false)
44
+ @raw_log_argument = log
45
+ @log = validated_log(log)
46
+ @out = false
47
+ @production = validated_production(production)
48
+
49
+ return unless enabled?
50
+
51
+ @logger = validated_logger(logger)
52
+ @logdev = validated_logdev(logdev)
53
+ @out = validated_out(out)
54
+
55
+ configure_logging
56
+ end
57
+
58
+ # @return [Boolean] +true+ if Loba is used; otherwise, +false+
59
+ def enabled?
60
+ production? || !Internal::Platform::WithinRails.production?
61
+ end
62
+
63
+ # @return [Boolean] +true+ if Loba is skipped (because of a production environment);
64
+ # otherwise, +false+
65
+ def disabled?
66
+ !enabled?
67
+ end
68
+
69
+ private
70
+
71
+ attr_reader :raw_log_argument
72
+
73
+ def validated_log(candidate_log)
74
+ Internal.boolean_cast(candidate_log)
75
+ end
76
+
77
+ def validated_logger(candidate_logger)
78
+ return if candidate_logger.nil?
79
+ raise InvalidLoggerOptionError unless candidate_logger.is_a?(::Logger)
80
+
81
+ @log = true unless log_explicit?
82
+
83
+ candidate_logger
84
+ end
85
+
86
+ def validated_logdev(candidate_logdev)
87
+ case candidate_logdev
88
+ when nil, String, IO, StringIO, File::NULL
89
+ candidate_logdev
90
+ else
91
+ raise InvalidLogdevOptionError
92
+ end
93
+ end
94
+
95
+ def validated_out(candidate_out)
96
+ will_output = !logging_to_stdout? && out_param_cast(candidate_out)
97
+
98
+ @log = true unless will_output || log_explicit?
99
+
100
+ will_output
101
+ end
102
+
103
+ def validated_production(candidate_production)
104
+ Internal.boolean_cast(candidate_production)
105
+ end
106
+
107
+ def log_explicit?
108
+ !raw_log_argument.nil?
109
+ end
110
+
111
+ def logging_to_stdout?
112
+ log? && ((logdev == $stdout) || (logdev == '$stdout'))
113
+ end
114
+
115
+ def configure_logging
116
+ @log &&= enabled?
117
+
118
+ @logger ||= default_logger if log?
119
+ end
120
+
121
+ def default_logger
122
+ if Internal::Platform::WithinRails.logger?
123
+ ::Rails.logger
124
+ else
125
+ ::Logger.new((logdev || $stdout), formatter: Internal::Platform::Formatter.new)
126
+ end
127
+ end
128
+
129
+ def out_param_cast(value)
130
+ case value
131
+ when true, TrueClass
132
+ true
133
+ when nil, false, FalseClass, File::NULL
134
+ false
135
+ when String, Integer, IO, StringIO
136
+ Internal.boolean_cast(value)
137
+ else
138
+ raise InvalidOutOptionError
139
+ end
140
+ end
141
+ end
142
+ end
143
+ end
@@ -15,9 +15,9 @@ module Loba
15
15
  reset!
16
16
  end
17
17
 
18
- # Increments timestamping, including attributes `timenum` and `timewas`
18
+ # Increments timestamping, including attributes +timenum+ and +timewas+
19
19
  # @return [Hash] timestamp details
20
- # * :number => [Integer] incremented count of pings so far (attribute `timenum`)
20
+ # * :number => [Integer] incremented count of pings so far (attribute +timenum+)
21
21
  # * :now => [Time] current date and time
22
22
  # * :change => [Float] difference in seconds from any previous ping or reset
23
23
  def ping
@@ -30,7 +30,7 @@ module Loba
30
30
  # @param argument [Symbol, Object] the value or variable for which information is
31
31
  # to be retrieved
32
32
  # @param inspect [Boolean] when true, force #inspect to be called against
33
- # `argument` when evaluating
33
+ # +argument+ when evaluating
34
34
  # @param depth [Integer] depth in call stack to start evaluation from
35
35
  # @return [String] value representation of argument for display
36
36
  def value(argument:, inspect: true, depth: 0)
@@ -46,7 +46,7 @@ module Loba
46
46
 
47
47
  # Builds a label for display based on the argument when instantiated.
48
48
  # If the argument (when instantiated) is not a symbol, it may not be possible
49
- # to infer a label; in that case, '[unknown value]' is returned.
49
+ # to infer a label; in that case, "[unknown value]"" is returned.
50
50
  #
51
51
  # @param argument [Symbol, Object] the value or variable for which information is
52
52
  # to be retrieved
@@ -73,8 +73,8 @@ module Loba
73
73
  # Evaluate an arguments value from where it's bound.
74
74
  # @param argument [Symbol, Object] the value or variable for which information is
75
75
  # to be retrieved
76
- # @param inspect [Boolean] when true, force #inspect to be called against
77
- # `argument` when evaluating
76
+ # @param inspect [Boolean] when true, force +#inspect+ to be called against
77
+ # +argument+ when evaluating
78
78
  # @param depth [Integer] depth in call stack to start evaluation from
79
79
  # @return [Object] value of the argument when Loba was invoked
80
80
  def evaluate(argument:, inspect: true, depth: 0)
@@ -16,8 +16,8 @@ module Loba
16
16
  # and a label should be supplied when instantiated.
17
17
  # @param label [String] when provided, an explicit label to use; will override any
18
18
  # possible inferred label
19
- # @param inspect [Boolean] when true, force #inspect to be called against
20
- # `argument` when evaluating
19
+ # @param inspect [Boolean] when true, force +#inspect+ to be called against
20
+ # +argument+ when evaluating
21
21
  # @param depth_offset [Integer] depth in call stack to start evaluation from
22
22
  #
23
23
  # @return [Hash] various detail about the value being analyzed
@@ -25,7 +25,7 @@ module Loba
25
25
  # * :line => [String] code line reference
26
26
  # * :value => [String] value of argument (if nil, '-nil-' is returned)
27
27
  # * :label => [String] label, ending with ":"
28
- # (if not possible to infer, '[unknown value]' is returned)
28
+ # (if not possible to infer, "[unknown value]" is returned)
29
29
  def phrases(argument:, label: nil, inspect: true, depth_offset: 0)
30
30
  depth = depth_offset.nil? ? 0 : depth_offset.to_i
31
31
  {
data/lib/loba/internal.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require_relative 'internal/platform'
2
+ require_relative 'internal/settings'
2
3
  require_relative 'internal/time_keeper'
3
4
  require_relative 'internal/value'
4
5
 
@@ -24,5 +25,31 @@ module Loba
24
25
  content[1...-1]
25
26
  end
26
27
  module_function :unquote
28
+
29
+ # Canonical set of values interpreted to be false.
30
+ # Adapted from Rails's ActiveModule::Type::Boolean (2024)
31
+ FALSE_VALUES = [
32
+ false, 0, nil, '',
33
+ '0', :'0',
34
+ 'f', :f,
35
+ 'F', :F,
36
+ 'false', :false, # rubocop:disable Lint/BooleanSymbol
37
+ 'FALSE', :FALSE,
38
+ 'off', :off,
39
+ 'OFF', :OFF
40
+ ].to_set.freeze
41
+ private_constant :FALSE_VALUES
42
+
43
+ # Casts any value to true or false (boolean)
44
+ #
45
+ # @param value [Object] the value to cast
46
+ #
47
+ # @return [true, false]
48
+ def boolean_cast(value)
49
+ return false if value.respond_to?(:empty) && value.empty?
50
+
51
+ !FALSE_VALUES.include?(value)
52
+ end
53
+ module_function :boolean_cast
27
54
  end
28
55
  end
@@ -0,0 +1,80 @@
1
+ module Loba # rubocop:disable Style/Documentation
2
+ # Outputs a timestamped notice, useful for quick traces to see the code path.
3
+ # Also does a simple elapsed time check since the previous timestamp notice to
4
+ # help with quick, minimalist profiling.
5
+ # @param production [boolean]
6
+ # set to +true+ if this timestamp notice is to be recorded
7
+ # when running in a Rails production environment
8
+ # @param log [boolean]
9
+ # set to +false+ if no logging is ever wanted
10
+ # (default when not in Rails and +logger+ is nil);
11
+ # set to +true+ if logging is always wanted (default when in Rails or
12
+ # when +logger+ is set or +out+ is false);
13
+ # @param logger [Logger] override logging with specified Ruby Logger
14
+ # @param logdev [nil, String, IO, File::NULL]
15
+ # custom log device to use (when not in Rails); ignored if +logger+ is set;
16
+ # must be filename or IO object
17
+ # @param out [boolean]
18
+ # set to +false+ if console output is to be suppressed
19
+ # @return [NilClass] nil
20
+ # @example Basic use
21
+ # def hello
22
+ # Loba.timestamp
23
+ # end
24
+ # #=> [TIMESTAMP] #=0001, diff=0.000463, at=1451615389.505411, in=/path/to/file.rb:2:in 'hello'
25
+ # @example Forced to output when in production environment
26
+ # def hello
27
+ # Loba.ts production: true # Loba.ts is a shorthand alias for Loba.timestamp
28
+ # end
29
+ # #=> [TIMESTAMP] #=0001, diff=0.000463, at=1451615389.505411, in=/path/to/file.rb:2:in 'hello'
30
+ # @example Forced to output to log in addition to $stdout
31
+ # def hello
32
+ # Loba.timestamp log: true
33
+ # end
34
+ # #=> [TIMESTAMP] #=0001, diff=0.000463, at=1451615389.505411, in=/path/to/file.rb:2:in 'hello'
35
+ # @note To avoid doubled output, if a non-Rails logger is to be logged to and +logdev+ is
36
+ # set to +$stdout+, then output will be suppressed (i.e., +settings.out+ is +false+).
37
+ # Doubled output can still occur; in that case, explicitly use +out: false+.
38
+ def timestamp( # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
39
+ production: false,
40
+ log: false,
41
+ logger: nil,
42
+ logdev: nil,
43
+ out: true
44
+ )
45
+ settings = Internal::Settings.new(
46
+ log: log, logger: logger, logdev: logdev, out: out, production: production
47
+ )
48
+
49
+ return unless settings.enabled?
50
+
51
+ # NOTE: while tempting, memoizing loba_logger can lead to surprises if
52
+ # Rails presence isn't constant
53
+ writer = Internal::Platform.writer(settings: settings)
54
+
55
+ begin
56
+ stats = Internal::TimeKeeper.instance.ping
57
+ writer.call(
58
+ # 60: light_black / grey
59
+ "#{Rainbow('[TIMESTAMP]').black.bg(60)}" \
60
+ "#{Rainbow(' #=').yellow.bg(:default)}" \
61
+ "#{format('%04d', stats[:number])}" \
62
+ "#{Rainbow(', diff=').yellow}" \
63
+ "#{format('%.6f', stats[:change])}" \
64
+ "#{Rainbow(', at=').yellow}" \
65
+ "#{format('%.6f', stats[:now].round(6).to_f)}" \
66
+ "#{Rainbow(" \t(in #{caller(1..1).first})").color(60)}" # warning: nested interpolation
67
+ )
68
+ rescue StandardError => e
69
+ writer.call Rainbow("[TIMESTAMP] #=FAIL, in=#{caller(1..1).first}, err=#{e}").red
70
+ end
71
+
72
+ nil
73
+ end
74
+ module_function :timestamp
75
+
76
+ # Shorthand alias for Loba.timestamp.
77
+ # @!method ts(production: false, log: false, logger: nil, logdev: nil, out: true)
78
+ alias ts timestamp
79
+ module_function :ts
80
+ end
data/lib/loba/value.rb ADDED
@@ -0,0 +1,104 @@
1
+ module Loba # rubocop:disable Style/Documentation
2
+ # Outputs a value notice showing value of provided argument including method and
3
+ # class identification.
4
+ # @param argument [various] (required) the value to be evaluated and shown; if given as
5
+ # a +Symbol+, a label based on the argument will proceed the value the argument refers to
6
+ # @param label [String] explicit label to be used instead of attempting
7
+ # to infer from the argument; default is to attempt to infer a label from the argument
8
+ # @param inspect [boolean] +true+ if this value notice is to use +#inspect+ against the
9
+ # content being evaluated; otherwise, +false+
10
+ # @param production [boolean]
11
+ # set to +true+ if the value notice is to be recorded
12
+ # when running in a Rails production environment
13
+ # @param log [boolean]
14
+ # set to +false+ if no logging is ever wanted
15
+ # (default when not in Rails and +logger+ is nil);
16
+ # set to +true+ if logging is always wanted (default when in Rails or
17
+ # when +logger+ is set or +out+ is false);
18
+ # @param logger [Logger] override logging with specified Ruby Logger
19
+ # @param logdev [nil, String, IO, File::NULL]
20
+ # custom log device to use (when not in Rails); ignored if +logger+ is set;
21
+ # must be filename or IO object
22
+ # @param out [boolean]
23
+ # set to +false+ if console output is to be suppressed
24
+ # @return [NilClass] nil
25
+ # @example Using Symbol as argument
26
+ # class HelloWorld
27
+ # def hello(name)
28
+ # Loba.value :name # putting Loba statement to far left helps remember to remove later
29
+ # puts "Hello, #{name}!"
30
+ # end
31
+ # end
32
+ # HelloWorld.new.hello("Charlie")
33
+ # #=> [HelloWorld#hello] name: Charlie (at /path/to/file/hello_world.rb:3:in 'hello')
34
+ # #=> Hello, Charlie!
35
+ # @example Using non-Symbol as argument
36
+ # class HelloWorld
37
+ # def hello(name)
38
+ # Loba.val name # Loba.val is a shorthand alias for Loba.value
39
+ # puts "Hello, #{name}!"
40
+ # end
41
+ # end
42
+ # HelloWorld.new.hello("Charlie")
43
+ # #=> [HelloWorld#hello] Charlie (at /path/to/file/hello_world.rb:3:in 'hello')
44
+ # #=> Hello, Charlie!
45
+ # @example Using non-Symbol as argument with a label
46
+ # class HelloWorld
47
+ # def hello(name)
48
+ # Loba.value name, "Name:"
49
+ # puts "Hello, #{name}!"
50
+ # end
51
+ # end
52
+ # HelloWorld.new.hello("Charlie")
53
+ # #=> [HelloWorld#hello] Name: Charlie (at /path/to/file/hello_world.rb:3:in 'hello')
54
+ # #=> Hello, Charlie!
55
+ # @note To avoid doubled output, if a non-Rails logger is to be logged to and +logdev+ is
56
+ # set to +$stdout+, then output will be suppressed (i.e., +settings.out+ is +false+).
57
+ # Doubled output can still occur; in that case, explicitly use +out: false+.
58
+ def value( # rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/ParameterLists
59
+ argument,
60
+ label: nil,
61
+ inspect: true,
62
+ production: false,
63
+ log: false,
64
+ logger: nil,
65
+ logdev: nil,
66
+ out: true
67
+ )
68
+ settings = Internal::Settings.new(
69
+ log: log, logger: logger, logdev: logdev, out: out, production: production
70
+ )
71
+
72
+ return unless settings.enabled?
73
+
74
+ text = Internal::Value.phrases(
75
+ argument: (argument.nil? ? :nil : argument),
76
+ label: label,
77
+ inspect: inspect,
78
+ depth_offset: 1
79
+ )
80
+
81
+ Internal::Platform.writer(settings: settings).call(
82
+ # NOTE: while tempting, memoizing Internal::Platform.logger can lead to surprises
83
+ # if Rails presence isn't constant
84
+ #
85
+ # warning: nested interpolation below (slight help to performance)
86
+ # 60: light_black
87
+ # 62: light_green
88
+ "#{Rainbow("#{text[:tag]} ").green.bg(:default)}" \
89
+ "#{Rainbow("#{text[:label]} ").color(62)}" \
90
+ "#{text[:value]}" \
91
+ "#{Rainbow(" \t(in #{text[:line]})").color(60)}"
92
+ )
93
+
94
+ nil
95
+ end
96
+ module_function :value
97
+
98
+ # rubocop:disable Layout/LineLength
99
+ # Shorthand alias for Loba.value.
100
+ # @!method val(argument, label: nil, inspect: true, production: false, log: false, logger: nil, logdev:nil, out: true)
101
+ alias val value
102
+ module_function :val
103
+ # rubocop:enable Layout/LineLength
104
+ end
data/lib/loba/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  module Loba
2
2
  # Semantic version number
3
- VERSION = '2.0.0'.freeze
3
+ VERSION = '2.1.0'.freeze
4
4
  end
data/lib/loba.rb CHANGED
@@ -1,143 +1,14 @@
1
1
  require 'loba/version'
2
+ require 'loba/error'
2
3
  require 'loba/internal'
3
4
 
4
5
  require 'binding_of_caller'
5
6
  require 'rainbow'
6
7
 
8
+ require 'loba/timestamp'
9
+ require 'loba/value'
10
+
7
11
  # Loba module for quick tracing of Ruby and Rails.
8
- # If a Rails application, will use Rails.logger.debug.
9
- # If not a Rails application, will use STDOUT.
12
+ # Will write to $stdout (generally) and, optionally, a log.
10
13
  module Loba
11
- # Outputs a timestamped notice, useful for quick traces to see the code path.
12
- # Also does a simple elapsed time check since the previous timestamp notice to
13
- # help with quick, minimalist profiling.
14
- # @param production [Boolean] set to true if this timestamp notice is
15
- # to be recorded when running in :production environment
16
- # @param log [Boolean] when false, will not write to Rails.logger if present;
17
- # when true, will write to Rails.logger if present
18
- # @return [NilClass] nil
19
- # @example Basic use
20
- # def hello
21
- # Loba.timestamp
22
- # end
23
- # #=> [TIMESTAMP] #=0001, diff=0.000463, at=1451615389.505411, in=/path/to/file.rb:2:in 'hello'
24
- # @example Forced to output when in production environment
25
- # def hello
26
- # Loba.ts production: true # Loba.ts is a shorthand alias for Loba.timestamp
27
- # end
28
- # #=> [TIMESTAMP] #=0001, diff=0.000463, at=1451615389.505411, in=/path/to/file.rb:2:in 'hello'
29
- # @example Forced to output to log (if Rails.logger present) in addition to $STDOUT
30
- # def hello
31
- # Loba.timestamp log: true
32
- # end
33
- # #=> [TIMESTAMP] #=0001, diff=0.000463, at=1451615389.505411, in=/path/to/file.rb:2:in 'hello'
34
- def timestamp(production: false, log: false) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
35
- return unless Internal::Platform.logging_ok?(production)
36
-
37
- # NOTE: while tempting, memoizing loba_logger can lead to surprises if
38
- # Rails presence isn't constant
39
- loba_logger = Internal::Platform.logger
40
-
41
- begin
42
- stats = Internal::TimeKeeper.instance.ping
43
- loba_logger.call(
44
- # 60: light_black / grey
45
- "#{Rainbow('[TIMESTAMP]').black.bg(60)}" \
46
- "#{Rainbow(' #=').yellow.bg(:default)}" \
47
- "#{format('%04d', stats[:number])}" \
48
- "#{Rainbow(', diff=').yellow}" \
49
- "#{format('%.6f', stats[:change])}" \
50
- "#{Rainbow(', at=').yellow}" \
51
- "#{format('%.6f', stats[:now].round(6).to_f)}" \
52
- "#{Rainbow(" \t(in #{caller(1..1).first})").color(60)}", # warning: nested interpolation
53
- !!log
54
- )
55
- rescue StandardError => e
56
- loba_logger.call Rainbow("[TIMESTAMP] #=FAIL, in=#{caller(1..1).first}, err=#{e}").red
57
- end
58
-
59
- nil
60
- end
61
- module_function :timestamp
62
-
63
- # Shorthand alias for Loba.timestamp.
64
- # @!method ts(production: false, log: false)
65
- alias ts timestamp
66
- module_function :ts
67
-
68
- # Outputs a value notice showing value of provided argument including method and
69
- # class identification.
70
- # @param argument [various] (required) the value to be evaluated and shown; if given as
71
- # a Symbol, a label based on the argument will proceed the value the argument refers to
72
- # @param label [String] explicit label to be used instead of attempting
73
- # to infer from the argument; default is to attempt to infer a label from the argument
74
- # @param inspect [Boolean] true if this value notice is to use #inspect against the
75
- # content being evaluated; otherwise, false
76
- # @param production [Boolean] set to true if this timestamp notice is
77
- # to be recorded when running in :production environment
78
- # @param log [Boolean] when false, will not write to Rails.logger if present;
79
- # when true, will write to Rails.logger if present
80
- # @return [NilClass] nil
81
- # @example Using Symbol as argument
82
- # class HelloWorld
83
- # def hello(name)
84
- # Loba.value :name # putting Loba statement to far left helps remember to remove later
85
- # puts "Hello, #{name}!"
86
- # end
87
- # end
88
- # HelloWorld.new.hello("Charlie")
89
- # #=> [HelloWorld#hello] name: Charlie (at /path/to/file/hello_world.rb:3:in `hello')
90
- # #=> Hello, Charlie!
91
- # @example Using non-Symbol as argument
92
- # class HelloWorld
93
- # def hello(name)
94
- # Loba.val name # Loba.val is a shorthand alias for Loba.value
95
- # puts "Hello, #{name}!"
96
- # end
97
- # end
98
- # HelloWorld.new.hello("Charlie")
99
- # #=> [HelloWorld#hello] Charlie (at /path/to/file/hello_world.rb:3:in `hello')
100
- # #=> Hello, Charlie!
101
- # @example Using non-Symbol as argument with a label
102
- # class HelloWorld
103
- # def hello(name)
104
- # Loba.value name, "Name:"
105
- # puts "Hello, #{name}!"
106
- # end
107
- # end
108
- # HelloWorld.new.hello("Charlie")
109
- # #=> [HelloWorld#hello] Name: Charlie (at /path/to/file/hello_world.rb:3:in `hello')
110
- # #=> Hello, Charlie!
111
- def value(argument, label: nil, inspect: true, production: false, log: false) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
112
- return nil unless Internal::Platform.logging_ok?(production)
113
-
114
- text = Internal::Value.phrases(
115
- argument: (argument.nil? ? :nil : argument),
116
- label: label,
117
- inspect: inspect,
118
- depth_offset: 1
119
- )
120
-
121
- Internal::Platform.logger.call(
122
- # NOTE: while tempting, memoizing Internal::Platform.logger can lead to surprises
123
- # if Rails presence isn't constant
124
- #
125
- # warning: nested interpolation below (slight help to performance)
126
- # 60: light_black
127
- # 62: light_green
128
- "#{Rainbow("#{text[:tag]} ").green.bg(:default)}" \
129
- "#{Rainbow("#{text[:label]} ").color(62)}" \
130
- "#{text[:value]}" \
131
- "#{Rainbow(" \t(in #{text[:line]})").color(60)}",
132
- !!log
133
- )
134
-
135
- nil
136
- end
137
- module_function :value
138
-
139
- # Shorthand alias for Loba.value.
140
- # @!method val(argument, label: nil, inspect: true, production: false, log: false)
141
- alias val value
142
- module_function :val
143
14
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: loba
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Richard Newman
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-07-09 00:00:00.000000000 Z
11
+ date: 2024-09-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: binding_of_caller
@@ -51,11 +51,17 @@ files:
51
51
  - README.md
52
52
  - SECURITY.md
53
53
  - lib/loba.rb
54
+ - lib/loba/error.rb
54
55
  - lib/loba/internal.rb
55
56
  - lib/loba/internal/platform.rb
57
+ - lib/loba/internal/platform/formatter.rb
58
+ - lib/loba/internal/platform/within_rails.rb
59
+ - lib/loba/internal/settings.rb
56
60
  - lib/loba/internal/time_keeper.rb
57
61
  - lib/loba/internal/value.rb
58
62
  - lib/loba/internal/value/value_helper.rb
63
+ - lib/loba/timestamp.rb
64
+ - lib/loba/value.rb
59
65
  - lib/loba/version.rb
60
66
  homepage: https://github.com/rdnewman/loba
61
67
  licenses:
@@ -66,7 +72,7 @@ metadata:
66
72
  changelog_uri: https://github.com/rdnewman/loba/blob/main/CHANGELOG.md
67
73
  documentation_uri: https://www.rubydoc.info/gems/loba
68
74
  rubygems_mfa_required: 'true'
69
- post_install_message:
75
+ post_install_message:
70
76
  rdoc_options: []
71
77
  require_paths:
72
78
  - lib
@@ -81,8 +87,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
81
87
  - !ruby/object:Gem::Version
82
88
  version: '0'
83
89
  requirements: []
84
- rubygems_version: 3.2.33
85
- signing_key:
90
+ rubygems_version: 3.5.11
91
+ signing_key:
86
92
  specification_version: 4
87
93
  summary: 'Loba: Easy tracing for debugging.'
88
94
  test_files: []