nrser 0.2.2 → 0.3.0

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.
Files changed (188) hide show
  1. checksums.yaml +4 -4
  2. data/lib/nrser/char/alpha_numeric_sub.rb +1 -2
  3. data/lib/nrser/char.rb +0 -6
  4. data/lib/nrser/core_ext/array.rb +120 -0
  5. data/lib/nrser/core_ext/binding.rb +44 -0
  6. data/lib/nrser/{functions → core_ext}/enumerable/find_map.rb +18 -15
  7. data/lib/nrser/{ext → core_ext}/enumerable.rb +10 -24
  8. data/lib/nrser/core_ext/exception.rb +30 -0
  9. data/lib/nrser/core_ext/hash/extract_values_at.rb +49 -0
  10. data/lib/nrser/core_ext/hash/transform_values_with_keys.rb +24 -0
  11. data/lib/nrser/core_ext/hash.rb +50 -0
  12. data/lib/nrser/core_ext/module/method_objects.rb +96 -0
  13. data/lib/nrser/core_ext/module/names.rb +69 -0
  14. data/lib/nrser/core_ext/module/source_locations.rb +214 -0
  15. data/lib/nrser/core_ext/module.rb +2 -0
  16. data/lib/nrser/core_ext/object/lazy_var.rb +31 -0
  17. data/lib/nrser/core_ext/object.rb +46 -0
  18. data/lib/nrser/core_ext/open_struct.rb +6 -0
  19. data/lib/nrser/{ext → core_ext}/pathname.rb +8 -5
  20. data/lib/nrser/{ext → core_ext}/string.rb +6 -12
  21. data/lib/nrser/core_ext/symbol.rb +13 -0
  22. data/lib/nrser/core_ext/time.rb +46 -0
  23. data/lib/nrser/core_ext.rb +13 -0
  24. data/lib/nrser/errors/abstract_method_error.rb +150 -0
  25. data/lib/nrser/errors/argument_error.rb +42 -0
  26. data/lib/nrser/errors/nicer_error.rb +298 -72
  27. data/lib/nrser/errors/type_error.rb +46 -0
  28. data/lib/nrser/errors.rb +4 -53
  29. data/lib/nrser/ext/tree.rb +3 -0
  30. data/lib/nrser/functions/enumerable/associate.rb +6 -9
  31. data/lib/nrser/functions/enumerable/include_slice.rb +2 -3
  32. data/lib/nrser/functions/enumerable.rb +1 -3
  33. data/lib/nrser/functions/exception.rb +1 -1
  34. data/lib/nrser/functions/hash.rb +0 -6
  35. data/lib/nrser/functions/merge_by.rb +2 -2
  36. data/lib/nrser/functions/module/method_objects.rb +77 -0
  37. data/lib/nrser/functions/module.rb +1 -2
  38. data/lib/nrser/functions/open_struct.rb +25 -35
  39. data/lib/nrser/functions/proc.rb +1 -6
  40. data/lib/nrser/functions/string/looks_like.rb +32 -1
  41. data/lib/nrser/functions/string.rb +1 -40
  42. data/lib/nrser/functions/text/lines.rb +2 -1
  43. data/lib/nrser/functions.rb +0 -1
  44. data/lib/nrser/graph/tsorter.rb +41 -0
  45. data/lib/nrser/labs/core_ext/binding.rb +37 -0
  46. data/lib/nrser/labs/stash.rb +372 -0
  47. data/lib/nrser/{logging → log}/appender/sync.rb +3 -3
  48. data/lib/nrser/log/appender.rb +3 -0
  49. data/lib/nrser/{logging → log}/formatters/color.rb +47 -20
  50. data/lib/nrser/log/formatters/mixin.rb +270 -0
  51. data/lib/nrser/{logging → log}/formatters.rb +0 -0
  52. data/lib/nrser/log/logger.rb +229 -0
  53. data/lib/nrser/log/mixin.rb +56 -0
  54. data/lib/nrser/log.rb +723 -0
  55. data/lib/nrser/message.rb +24 -3
  56. data/lib/nrser/meta/source/location.rb +158 -0
  57. data/lib/nrser/meta.rb +1 -1
  58. data/lib/nrser/props/class_methods.rb +118 -0
  59. data/lib/nrser/props/immutable/hash.rb +111 -0
  60. data/lib/nrser/props/immutable/hash_variable.rb +82 -0
  61. data/lib/nrser/props/immutable/instance_variables.rb +48 -0
  62. data/lib/nrser/props/immutable/vector.rb +107 -0
  63. data/lib/nrser/props/instance_methods.rb +184 -0
  64. data/lib/nrser/props/metadata.rb +359 -0
  65. data/lib/nrser/props/mutable/instance_variables.rb +60 -0
  66. data/lib/nrser/props/mutable/stash.rb +199 -0
  67. data/lib/nrser/{meta/props → props}/prop.rb +217 -112
  68. data/lib/nrser/props/storage/instance_variable.rb +85 -0
  69. data/lib/nrser/props/storage/instance_variables.rb +67 -0
  70. data/lib/nrser/props/storage/key.rb +88 -0
  71. data/lib/nrser/props.rb +9 -0
  72. data/lib/nrser/refinements/sugar.rb +41 -0
  73. data/lib/nrser/refinements/types.rb +2 -2
  74. data/lib/nrser/refinements.rb +14 -16
  75. data/lib/nrser/rspex/example_group/describe_attribute.rb +24 -0
  76. data/lib/nrser/rspex/example_group/describe_called_with.rb +1 -6
  77. data/lib/nrser/rspex/example_group/{describe_use_case.rb → describe_case.rb} +6 -3
  78. data/lib/nrser/rspex/example_group/describe_class.rb +1 -0
  79. data/lib/nrser/rspex/example_group/describe_group.rb +29 -0
  80. data/lib/nrser/rspex/example_group/describe_instance_method.rb +2 -2
  81. data/lib/nrser/rspex/example_group/describe_message.rb +35 -0
  82. data/lib/nrser/rspex/example_group/describe_method.rb +23 -2
  83. data/lib/nrser/rspex/example_group/describe_module.rb +19 -0
  84. data/lib/nrser/rspex/example_group/describe_response_to.rb +32 -0
  85. data/lib/nrser/rspex/example_group/describe_section.rb +38 -0
  86. data/lib/nrser/rspex/example_group/describe_sent_to.rb +52 -0
  87. data/lib/nrser/rspex/example_group/describe_source_file.rb +49 -0
  88. data/lib/nrser/rspex/example_group/describe_spec_file.rb +41 -108
  89. data/lib/nrser/rspex/example_group/describe_when.rb +14 -7
  90. data/lib/nrser/rspex/example_group/describe_x.rb +39 -12
  91. data/lib/nrser/rspex/example_group/overrides.rb +66 -0
  92. data/lib/nrser/rspex/example_group.rb +20 -252
  93. data/lib/nrser/rspex/format.rb +83 -17
  94. data/lib/nrser/rspex.rb +4 -34
  95. data/lib/nrser/sugar/method_missing_forwarder.rb +50 -0
  96. data/lib/nrser/{env → sys/env}/path.rb +1 -2
  97. data/lib/nrser/{env.rb → sys/env.rb} +2 -1
  98. data/lib/nrser/sys.rb +5 -0
  99. data/lib/nrser/types/any.rb +36 -7
  100. data/lib/nrser/types/{array.rb → arrays.rb} +32 -81
  101. data/lib/nrser/types/attrs.rb +68 -15
  102. data/lib/nrser/types/booleans.rb +95 -34
  103. data/lib/nrser/types/bounded.rb +12 -10
  104. data/lib/nrser/types/combinators.rb +74 -37
  105. data/lib/nrser/types/errors/check_error.rb +86 -0
  106. data/lib/nrser/types/errors/from_string_error.rb +82 -0
  107. data/lib/nrser/types/factory.rb +91 -0
  108. data/lib/nrser/types/hashes.rb +171 -26
  109. data/lib/nrser/types/in.rb +25 -12
  110. data/lib/nrser/types/is.rb +50 -18
  111. data/lib/nrser/types/is_a.rb +52 -33
  112. data/lib/nrser/types/labels.rb +6 -33
  113. data/lib/nrser/types/maybe.rb +12 -4
  114. data/lib/nrser/types/nil.rb +24 -4
  115. data/lib/nrser/types/not.rb +6 -16
  116. data/lib/nrser/types/numbers.rb +94 -57
  117. data/lib/nrser/types/pairs.rb +57 -57
  118. data/lib/nrser/types/paths.rb +112 -133
  119. data/lib/nrser/types/responds.rb +64 -74
  120. data/lib/nrser/types/shape.rb +29 -24
  121. data/lib/nrser/types/strings.rb +25 -17
  122. data/lib/nrser/types/symbols.rb +19 -17
  123. data/lib/nrser/types/trees.rb +18 -70
  124. data/lib/nrser/types/tuples.rb +36 -40
  125. data/lib/nrser/types/type.rb +342 -91
  126. data/lib/nrser/types/when.rb +40 -18
  127. data/lib/nrser/types/where.rb +94 -9
  128. data/lib/nrser/types.rb +72 -63
  129. data/lib/nrser/version.rb +1 -1
  130. data/lib/nrser.rb +18 -18
  131. data/spec/lib/nrser/{functions/binding/template_spec.rb → core_ext/binding/erb_spec.rb} +5 -5
  132. data/spec/lib/nrser/{functions → core_ext}/enumerable/find_map_spec.rb +8 -6
  133. data/spec/lib/nrser/{refinements → core_ext}/hash_spec.rb +9 -22
  134. data/spec/lib/nrser/errors/abstract_method_error_spec.rb +12 -5
  135. data/spec/lib/nrser/functions/enumerable/{to_h_by_spec.rb → associate_spec.rb} +1 -1
  136. data/spec/lib/nrser/functions/merge_by_spec.rb +1 -1
  137. data/spec/lib/nrser/functions/tree/each_branch_spec.rb +3 -3
  138. data/spec/lib/nrser/functions/tree/transform_spec.rb +14 -15
  139. data/spec/lib/nrser/gem_ext/hamster/json_spec.rb +4 -0
  140. data/spec/lib/nrser/meta/source/location_spec.rb +86 -0
  141. data/spec/lib/nrser/props/immutable/hash_spec.rb +297 -0
  142. data/spec/lib/nrser/props/immutable/vector_spec.rb +296 -0
  143. data/spec/lib/nrser/{meta/props_spec.rb → props/original_props_spec.rb} +11 -16
  144. data/spec/lib/nrser/{meta/props → props}/to_and_from_data_spec.rb +10 -8
  145. data/spec/lib/nrser/refinements/array_spec.rb +2 -15
  146. data/spec/lib/nrser/refinements/erb_spec.rb +5 -7
  147. data/spec/lib/nrser/refinements/set_spec.rb +2 -15
  148. data/spec/lib/nrser/{env → sys/env}/path/insert_spec.rb +4 -2
  149. data/spec/lib/nrser/{env → sys/env}/path_spec.rb +4 -2
  150. data/spec/lib/nrser/types/array_spec.rb +8 -8
  151. data/spec/lib/nrser/types/paths_spec.rb +15 -18
  152. data/spec/spec_helper.rb +4 -0
  153. metadata +109 -69
  154. data/lib/nrser/ext/binding.rb +0 -36
  155. data/lib/nrser/ext/module.rb +0 -62
  156. data/lib/nrser/ext.rb +0 -8
  157. data/lib/nrser/functions/binding.rb +0 -76
  158. data/lib/nrser/functions/enumerable/map_keys.rb +0 -0
  159. data/lib/nrser/functions/enumerable/map_values.rb +0 -94
  160. data/lib/nrser/functions/hash/deep_merge.rb +0 -57
  161. data/lib/nrser/functions/hash/except_keys.rb +0 -44
  162. data/lib/nrser/functions/hash/slice_keys.rb +0 -43
  163. data/lib/nrser/functions/hash/stringify_keys.rb +0 -55
  164. data/lib/nrser/functions/hash/symbolize_keys.rb +0 -57
  165. data/lib/nrser/functions/hash/transform_keys.rb +0 -140
  166. data/lib/nrser/functions/module/methods.rb +0 -206
  167. data/lib/nrser/functions/module/source_locations.rb +0 -213
  168. data/lib/nrser/logging/appender.rb +0 -3
  169. data/lib/nrser/logging.rb +0 -353
  170. data/lib/nrser/meta/props/base.rb +0 -31
  171. data/lib/nrser/meta/props.rb +0 -357
  172. data/lib/nrser/refinements/array.rb +0 -133
  173. data/lib/nrser/refinements/binding.rb +0 -6
  174. data/lib/nrser/refinements/enumerator.rb +0 -5
  175. data/lib/nrser/refinements/exception.rb +0 -35
  176. data/lib/nrser/refinements/hash.rb +0 -150
  177. data/lib/nrser/refinements/module.rb +0 -5
  178. data/lib/nrser/refinements/object.rb +0 -42
  179. data/lib/nrser/refinements/open_struct.rb +0 -28
  180. data/lib/nrser/refinements/pathname.rb +0 -5
  181. data/lib/nrser/refinements/set.rb +0 -5
  182. data/lib/nrser/refinements/string.rb +0 -5
  183. data/lib/nrser/refinements/symbol.rb +0 -20
  184. data/lib/nrser/rspex/described.rb +0 -99
  185. data/spec/design/mapping_spec.rb +0 -42
  186. data/spec/lib/nrser/functions/hash_spec.rb +0 -41
  187. data/spec/lib/nrser/functions/string/truncate_spec.rb +0 -11
  188. data/spec/lib/nrser/refinements/truncate_spec.rb +0 -10
data/lib/nrser/log.rb ADDED
@@ -0,0 +1,723 @@
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
3
+
4
+ # Requirements
5
+ # =======================================================================
6
+
7
+ # Stdlib
8
+ # -----------------------------------------------------------------------
9
+
10
+ # Deps
11
+ # -----------------------------------------------------------------------
12
+
13
+ # What NRSER's logging is based off
14
+ require 'semantic_logger'
15
+
16
+ # We need a {Concurrent::Map} to hold reference to loggers.
17
+ require "concurrent/map"
18
+
19
+ # Project / Package
20
+ # -----------------------------------------------------------------------
21
+
22
+
23
+ # Definitions
24
+ # =======================================================================
25
+
26
+ # Unified logging support via {SemanticLogger}.
27
+ #
28
+ # @see https://rocketjob.github.io/semantic_logger/index.html
29
+ #
30
+ module NRSER::Log
31
+
32
+ # Sub-Tree Requirements
33
+ # ========================================================================
34
+
35
+ require_relative './log/mixin'
36
+ require_relative './log/logger'
37
+ require_relative './log/formatters'
38
+ require_relative './log/appender'
39
+
40
+
41
+ # Constants
42
+ # ========================================================================
43
+
44
+
45
+ # Mixins
46
+ # ========================================================================
47
+
48
+ # Mix in {.logger} and {#logger}
49
+ include Mixin
50
+
51
+ # We want to forward some methods directly to {SemanticLogger}
52
+ extend SingleForwardable
53
+
54
+
55
+ # Delegation
56
+ # ========================================================================
57
+ #
58
+ # Send some things up to {SemanticLogger}.
59
+ #
60
+
61
+ def_single_delegators(
62
+ SemanticLogger,
63
+ :application,
64
+ :application=,
65
+ :[],
66
+ # NOTE These are funky due to different in SemLog's int level and Ruby
67
+ # stdlib / Rails logger int levels, so omit for now.
68
+ #
69
+ # :index_to_level,
70
+ # :level_to_index
71
+ )
72
+
73
+
74
+ # Module Attributes
75
+ # ========================================================================
76
+
77
+ # Used in {.setup!} to make sure we don't have multiple threads trying to
78
+ # muck around at the same time.
79
+ #
80
+ @__mutex__ = Mutex.new
81
+
82
+ # We need to store references to {NRSER::Log::Logger} objects by name so
83
+ # we can apply rules that are added afterwards.
84
+ #
85
+ @__loggers__ = Concurrent::Map.new
86
+
87
+
88
+ # Class Methods
89
+ # ========================================================================
90
+
91
+ def self.[] subject
92
+ # key = logger_type_and_name_from subject
93
+ #
94
+ # if @__loggers__.key? key
95
+ # ref = @__loggers__[key]
96
+ #
97
+ # if ref.weakref_alive?
98
+ # return
99
+ #
100
+ instance = NRSER::Log::Logger.new subject
101
+ end
102
+
103
+
104
+ # @!group Utility Class Methods
105
+ # ------------------------------------------------------------------------
106
+
107
+
108
+ # @todo Document logger_name_and_type method.
109
+ #
110
+ # @param [type] arg_name
111
+ # @todo Add name param description.
112
+ #
113
+ # @return [return_type]
114
+ # @todo Document return value.
115
+ #
116
+ def self.logger_type_and_name_from subject
117
+ case subject
118
+ when String
119
+ [:string, subject]
120
+
121
+ when Module
122
+ [:const, subject.safe_name]
123
+
124
+ when Array
125
+ # NOTE Prob bad to use {NRSER::Types} here since logging gets
126
+ # required so early, and we want it to *work* then... seems like
127
+ # it would introduce lots of dependency mess. So just use plain
128
+ # ol' Ruby.
129
+ unless subject.length == 2 &&
130
+ subject[0].is_a?( Symbol ) &&
131
+ subject[1].is_a?( String )
132
+ raise NRSER::ArgumentError.new \
133
+ "Subject arrays must be [Symbol, String]; received", subject,
134
+ subject: subject,
135
+ details: -> {
136
+ <<~END
137
+ When passing an {Array}, it must be a pair:
138
+
139
+ 1. `[0]` must be a {Symbol} that is the logger's subject
140
+ *type*.
141
+
142
+ 2. `[1]` must be a {String} that is the logger's subject
143
+ *name*.
144
+ END
145
+ }
146
+ end
147
+
148
+ pair = subject.dup
149
+ pair[0] = :const if [:module, :class].include? pair[0]
150
+ pair
151
+
152
+ when Hash
153
+ unless subject.length == 1
154
+ raise NRSER::ArgumentError.new \
155
+ "Hash subjects must be a single key/value pair",
156
+ subject: subject
157
+ end
158
+
159
+ pair = subject.first
160
+
161
+ unless pair[0].is_a?( Symbol ) &&
162
+ pair[1].is_a?( String )
163
+ raise NRSER::ArgumentError.new \
164
+ "Subject hashes must be a Symbol key and String value",
165
+ subject: subject
166
+ end
167
+
168
+ pair[0] = :const if [:module, :class].include? pair[0]
169
+
170
+ pair
171
+
172
+ else
173
+ raise NRSER::TypeError.new \
174
+ "Expected `subject` to be String, Module, Array or Hash, ",
175
+ "found #{ subject.class }",
176
+ subject: subject
177
+ end
178
+ end # .logger_type_and_name_from
179
+
180
+
181
+ # Normalize a level name or number to a symbol, raising if it's not valid.
182
+ #
183
+ # Relies on Semantic Logger's "internal" {SemanticLogger.level_to_index}
184
+ # method.
185
+ #
186
+ # @see https://github.com/rocketjob/semantic_logger/blob/97247126de32e6ecbf74cbccaa3b3732768d52c5/lib/semantic_logger/semantic_logger.rb#L454
187
+ #
188
+ # @param [Symbol | String | Integer]
189
+ # Representation of a level in one of the following formats:
190
+ #
191
+ # 1. {Symbol} - verified as member of {SemanticLogger::LEVELS} and
192
+ # returned.
193
+ #
194
+ # 2. {String} - accepts string representations of the level symbols,
195
+ # case insensitive.
196
+ #
197
+ # 3. {Integer} - interpreted as a Ruby StdLib Logger / Rails Logger
198
+ # level, which are **different** than Semantic Logger's!
199
+ #
200
+ # @return [:trace | :debug | :info | :warn | :error | :fatal]
201
+ # Log level symbol.
202
+ #
203
+ # @raise
204
+ # When `level` is invalid.
205
+ #
206
+ def self.level_sym_for level
207
+ if SemanticLogger::LEVELS.include? level
208
+ level
209
+ else
210
+ SemanticLogger.index_to_level SemanticLogger.level_to_index( level )
211
+ end
212
+ end
213
+
214
+
215
+ # Global / default log level, which we always normalize to a symbol.
216
+ #
217
+ # @return [:trace | :debug | :info | :warn | :error | :fatal]
218
+ #
219
+ def self.level
220
+ level_sym_for SemanticLogger.default_level
221
+ end
222
+
223
+
224
+ # Integer level index. Forwards to {SemanticLogger.default_level_index}.
225
+ #
226
+ # @note
227
+ # There is some funkiness around level indexes that I think/hope I wrote
228
+ # down somewhere, so use with some caution/research.
229
+ #
230
+ # @return [Fixnum]
231
+ #
232
+ def self.level_index
233
+ SemanticLogger.default_level_index
234
+ end
235
+
236
+
237
+ # Set the global default log level.
238
+ #
239
+ # @param level (see .level_sym_for)
240
+ # @return (see .level_sym_for)
241
+ # @raise (see .level_sym_for)
242
+ #
243
+ def self.level= level
244
+ SemanticLogger.default_level = level_sym_for level
245
+ end
246
+
247
+
248
+ def self.level_from_ENV prefix:
249
+ if NRSER.truthy? ENV["#{ prefix }_TRACE"]
250
+ return :trace
251
+ elsif NRSER.truthy? ENV["#{ prefix }_DEBUG"]
252
+ return :debug
253
+ end
254
+
255
+ level = ENV["#{ prefix }_LOG_LEVEL"]
256
+
257
+ unless level.nil? || level == ''
258
+ return level
259
+ end
260
+
261
+ nil
262
+ end
263
+
264
+ # @!endgroup Utility Class Methods
265
+
266
+
267
+ # @!group Setup Class Methods
268
+ # --------------------------------------------------------------------------
269
+
270
+ # Setup logging.
271
+ #
272
+ # @param [type] arg_name
273
+ # @todo Add name param description.
274
+ #
275
+ # @return [nil]
276
+ #
277
+ def self.setup! level: nil,
278
+ dest: nil,
279
+ sync: nil,
280
+ say_hi: :debug,
281
+ application: nil,
282
+ env_var_prefix: nil,
283
+ header: nil,
284
+ body: nil
285
+
286
+ unless @__mutex__.try_lock
287
+ raise ThreadError, <<~END
288
+ Mutex is already held.
289
+
290
+ You should pretty generally NOT have multiple threads trying to
291
+ setup logging at once or re-enter {NRSER::Log.setup}!
292
+ END
293
+ end
294
+
295
+ # Wrap around everything to make sure we release the mutex
296
+ begin
297
+ # Setup main appender if needed
298
+ setup_appender! dest
299
+
300
+ # Set sync/async processor state
301
+ setup_sync! sync
302
+
303
+ # If we didn't receive a level, check the ENV
304
+ if level.nil?
305
+ if env_var_prefix.nil? && !application.nil?
306
+ env_var_prefix = application.gsub( /[^a-zA-Z0-0_]+/, '_' ).upcase
307
+ end
308
+
309
+ level = level_from_ENV prefix: env_var_prefix
310
+ end
311
+
312
+ # If we ended up with a level, try to set it (will only log a warning
313
+ # if it fails, not raise, which could crash things on boot)
314
+ setup_level! level unless level.nil?
315
+
316
+ self.application = application unless application.nil?
317
+
318
+ # Setup formatter header and body tokens, if needed
319
+ setup_formatter_tokens! :header, header
320
+ setup_formatter_tokens! :body, body
321
+
322
+ ensure
323
+ # Make sure we release the mutex; don't need to hold it for the rest
324
+ @__mutex__.unlock
325
+ end
326
+
327
+ # Name the main thread so that `process_info` doesn't look so lame
328
+ setup_main_thread_name!
329
+
330
+ # Possibly say hi
331
+ setup_say_hi say_hi, dest, sync
332
+
333
+ nil
334
+
335
+ rescue Exception => error
336
+ # Suppress errors in favor of a warning
337
+
338
+ logger.warn \
339
+ message: "Error setting up logging",
340
+ payload: {
341
+ args: {
342
+ level: level,
343
+ dest: dest,
344
+ env_var_prefix: env_var_prefix,
345
+ say_hi: say_hi,
346
+ },
347
+ },
348
+ exception: error
349
+
350
+ nil
351
+ end # .setup!
352
+
353
+
354
+ # Call {.setup!} with some default keywords that are nice for CLI apps.
355
+ #
356
+ # @param (see .setup!)
357
+ # @return (see .setup!)
358
+ #
359
+ def self.setup_for_CLI! dest: $stderr,
360
+ sync: true,
361
+ **kwds
362
+ setup! dest: dest, sync: sync, **kwds
363
+ end # .setup_for_CLI!
364
+
365
+ # Old name
366
+ singleton_class.send :alias_method, :setup_for_cli!, :setup_for_CLI!
367
+
368
+
369
+ # Call {.setup!} with some default keywords that are nice for interactive
370
+ # session (console/REPL) usage.
371
+ #
372
+ # @param (see .setup!)
373
+ # @return (see .setup!)
374
+ #
375
+ def self.setup_for_console! dest: $stderr,
376
+ sync: true,
377
+ header: { delete: :process_info },
378
+ **kwds
379
+ setup! \
380
+ dest: dest,
381
+ sync: sync,
382
+ header: header,
383
+ **kwds
384
+ end # .setup_for_console!
385
+
386
+
387
+ # Call {.setup!} but provides default for running RSpec tests: sync,
388
+ # write to
389
+ #
390
+ # @param (see .setup!)
391
+ # @return (see .setup!)
392
+ #
393
+ def self.setup_for_rspec! dest: $stderr,
394
+ sync: true,
395
+ header: { delete: :process_info },
396
+ **kwds
397
+ setup! \
398
+ dest: dest,
399
+ sync: sync,
400
+ header: header,
401
+ **kwds
402
+ end # .setup_for_rspec!
403
+
404
+ # @!endgroup Setup Class Methods
405
+
406
+ # ************************************************************************
407
+
408
+
409
+ # Shortcut to {SemanticLogger::Processor.instance}.
410
+ #
411
+ # @return [SemanticLogger::Subscriber]
412
+ # You would think this would be a {SemanticLogger::Processor}, but it's
413
+ # actually an *appender* ({SemanticLogger::Subscriber} is the base class
414
+ # of appenders, sigh...).
415
+ #
416
+ def self.processor
417
+ SemanticLogger::Processor.instance
418
+ end
419
+
420
+
421
+ def self.sync?
422
+ processor.is_a? NRSER::Log::Appender::Sync
423
+ end
424
+
425
+
426
+ # The current "main" appender (destination), if any.
427
+ #
428
+ # This is just to simplify things in simple cases, you can always still
429
+ # add multiple appenders.
430
+ #
431
+ # @return [SemanticLogger::Subscriber | nil]
432
+ #
433
+ def self.appender
434
+ @appender
435
+ end
436
+
437
+
438
+ # Short-cut for `.appender.formatter`.
439
+ #
440
+ # @return [nil]
441
+ # If there is no {.appender}.
442
+ #
443
+ # @return [SemanticLogger::Formatters::Default]
444
+ # If there is an {.appender}, the appender's `#formatter` attribute.
445
+ #
446
+ def self.formatter
447
+ appender.formatter if appender
448
+ end
449
+
450
+
451
+ # Is there a header formatter?
452
+ #
453
+ # @return [Boolean]
454
+ # `true` if there is an {.formatter} and it responds to ':header'.
455
+ #
456
+ # If it returns `false`, it means there is no {.appender} attached
457
+ # or it's formatter does not mix in {NRSER::Log::Formatters::Mixin}.
458
+ #
459
+ # In this case you can't read or write to the header, so {.header=}
460
+ # won't do anything.
461
+ #
462
+ def self.header?
463
+ formatter && formatter.respond_to?( :header )
464
+ end
465
+
466
+
467
+ # Calls `.formatter.header` if there is a {.header?}.
468
+ #
469
+ # @see NRSER::Log::Formatters::Mixin#header
470
+ # @param (see NRSER::Log::Formatters::Mixin#header)
471
+ # @return (see NRSER::Log::Formatters::Mixin#header)
472
+ # @raise (see NRSER::Log::Formatters::Mixin#header)
473
+ #
474
+ # @return [nil]
475
+ # If there is no {.appender} or it's formatter doesn't have a header.
476
+ #
477
+ def self.header *tokens
478
+ formatter.header( *tokens ) if header?
479
+ end
480
+
481
+
482
+ def self.header= tokens
483
+ if header?
484
+ formatter.header = tokens
485
+ end
486
+ end
487
+
488
+
489
+ def self.body?
490
+ formatter && formatter.respond_to?( :body )
491
+ end
492
+
493
+
494
+ def self.body *tokens
495
+ formatter.body( *tokens ) if body?
496
+ end
497
+
498
+
499
+ def self.body= tokens
500
+ if body?
501
+ formatter.body = tokens
502
+ end
503
+ end
504
+
505
+
506
+ # @!group Setup Helpers
507
+ # ------------------------------------------------------------------------
508
+ #
509
+ # Break-outs from the monstrosity that {#setup!} became. Only called
510
+ # from there, and only *should* be called from there! Hence these methods
511
+ # are all private as well.
512
+ #
513
+
514
+ # Try to set the level, logging a warning and returning `nil` if it fails.
515
+ #
516
+ # @param level (see .level=)
517
+ #
518
+ # @return [Symbol]
519
+ # The level symbol if it was set successfully.
520
+ #
521
+ # @return [nil]
522
+ # If the set failed (also logs a warning).
523
+ #
524
+ def self.setup_level! level
525
+ logger.catch.warn(
526
+ "Unable to set level, probably bad value",
527
+ level: level
528
+ ) do
529
+ self.level = level
530
+ end
531
+ end # .try_set_level
532
+
533
+ private_class_method :setup_level!
534
+
535
+
536
+ # Possibly say hi. Params are from {#setup!}.
537
+ #
538
+ # @private
539
+ # @return [nil]
540
+ #
541
+ def self.setup_say_hi say_hi, dest, sync
542
+ will_say_hi = case say_hi
543
+ when true, false
544
+ say_hi
545
+ when Symbol, String, Fixnum
546
+ logger.catch( on_fail: false ).warn(
547
+ "Bad `say_hi` kwd in {NRSER::Log.setup}",
548
+ say_hi: say_hi,
549
+ expected: "Symbol, String, or Fixnum representing log level"
550
+ ) do
551
+ level_index < SemanticLogger.level_to_index( say_hi )
552
+ end
553
+
554
+ else
555
+ logger.warn "Bad `say_hi` kwd in {NRSER::Log.setup}",
556
+ say_hi: say_hi,
557
+ expected: [true, false, Symbol, String, Fixnum]
558
+
559
+ false
560
+ end
561
+
562
+ if will_say_hi
563
+ logger.info "Hi! Logging is setup",
564
+ level: self.level,
565
+ dest: dest,
566
+ sync: sync
567
+ end
568
+
569
+ nil
570
+ end # .setup_say_hi
571
+
572
+ private_class_method :setup_say_hi
573
+
574
+
575
+ # Make sure the main thread has a {Thread#name} (a core_ext added by
576
+ # SemanticLogger).
577
+ #
578
+ # We do this so that the `process_info` section in log messages isn't so
579
+ # distracting and useless ({Thread#name} defaults to the thread's
580
+ # `#object_id`).
581
+ #
582
+ # If it has no name, we name it "main".
583
+ #
584
+ # @private
585
+ # @return [nil]
586
+ #
587
+ def self.setup_main_thread_name!
588
+ main = Thread.main
589
+ main.name = 'main' unless main.instance_variable_defined? :@name
590
+ nil
591
+ end # .name_main_thread
592
+
593
+ private_class_method :setup_main_thread_name!
594
+
595
+
596
+ def self.setup_sync! sync
597
+ # Do nothing if `sync` is `nil`
598
+ return nil if sync.nil?
599
+
600
+ # Make sure we have a bool
601
+ bool = !!sync
602
+
603
+ # Take no action if we're already in the desired state
604
+ return bool if bool == sync?
605
+
606
+ # Ok, need to make a change
607
+ if sync?
608
+ # Switch to async
609
+
610
+ # We *should* already have the async processor
611
+ @async_processor ||= SemanticLogger::Appender::Async.new(
612
+ name: 'SemanticLogger::Processor',
613
+ appender: SemanticLogger::Processor.instance.appender,
614
+ max_queue_size: -1,
615
+ )
616
+
617
+ @sync_processor ||= SemanticLogger::Processor.instance
618
+
619
+ # Swap the async in for our sync
620
+ SemanticLogger::Processor.instance_variable_set \
621
+ :@processor,
622
+ @async_processor
623
+
624
+ else
625
+ @async_processor ||= SemanticLogger::Processor.instance
626
+ @sync_processor ||= NRSER::Log::Appender::Sync.new \
627
+ appender: SemanticLogger::Processor.instance.appender
628
+
629
+ # Swap our sync in for the async
630
+ SemanticLogger::Processor.instance_variable_set \
631
+ :@processor,
632
+ @sync_processor
633
+ end
634
+
635
+ bool
636
+ end
637
+
638
+ private_class_method :setup_sync!
639
+
640
+
641
+ # Setup formatter tokens for the {#header} or {#body}.
642
+ #
643
+ # @private
644
+ #
645
+ # @param [:header | :body] name
646
+ # What formatter tokens we're setting up.
647
+ #
648
+ # @return [nil]
649
+ #
650
+ def self.setup_formatter_tokens! name, arg
651
+ # Bail out on `nil`
652
+ return nil if arg.nil?
653
+
654
+ # `self.header` or `self.body`
655
+ target = send name
656
+
657
+ # Bail out if we don't have it
658
+ return nil if target.nil?
659
+
660
+ case arg
661
+ when Array
662
+ # It's an array, just set it through the forwarder method
663
+ send "#{ name }=", arg
664
+ when Hash
665
+ # It's a hash, so look for a `:delete` or `:remove` key, and delete
666
+ # each of those from the target
667
+ Array( arg.fetch( :delete, arg[:remove] ) ).
668
+ each { |token| target.delete token.try( :to_sym ) }
669
+ end
670
+
671
+ nil
672
+ end # .setup_formatter_tokens!
673
+
674
+ private_class_method :setup_formatter_tokens!
675
+
676
+
677
+ # @param [SemanticLogger::Subscriber | Hash | String | Pathname | IO] dest
678
+ # Where to log with the "main" appender (what goes in {#appender}).
679
+ #
680
+ def self.setup_appender! dest
681
+ # Bail out if nothing to do
682
+ return nil if dest.nil?
683
+
684
+ # Save ref to current appender (if any) so we can remove it after adding
685
+ # the new one.
686
+ old_appender = @appender
687
+
688
+ @appender = case dest
689
+ when SemanticLogger::Subscriber, Hash
690
+ # Can be handled directly
691
+ SemanticLogger.add_appender dest
692
+
693
+ when String, Pathname
694
+ # Assume these are file paths
695
+ SemanticLogger.add_appender file_name: dest.to_s
696
+
697
+ else
698
+ SemanticLogger.add_appender \
699
+ io: dest,
700
+ formatter: NRSER::Log::Formatters::Color.new
701
+ end
702
+
703
+ # Remove the old appender (if there was one). This is done after adding
704
+ # the new one so that failing won't result with no appenders.
705
+ SemanticLogger.remove_appender( old_appender ) if old_appender
706
+
707
+ @appender
708
+ end
709
+
710
+ private_class_method :setup_appender!
711
+
712
+
713
+ # @!endgroup Setup Helpers
714
+
715
+ end # module NRSER::Log
716
+
717
+
718
+ # Post-Processing
719
+ # ========================================================================
720
+
721
+ # Mix-in the Mixin to NRSER itself
722
+ #
723
+ NRSER.include NRSER::Log::Mixin