nrser 0.2.2 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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