nrser 0.3.1 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: bbe345fdd17d3661a6ab8424078866fca405486c
4
- data.tar.gz: 011ea7b181ad4f101ce83a1edc9a44ea5a4728fb
3
+ metadata.gz: 1c1aebae949432774359be83991d38a1f2401011
4
+ data.tar.gz: 4c30490c2fd5fdab98b488e20a1fbc3a1b7b6273
5
5
  SHA512:
6
- metadata.gz: cef54bd329af2caee3fb30220f39a57510d4a110836f86dfa7f2af744b24df8592e09f04ca27f27cbe548bb2229532e36afa2c668e2fc431ad564c4fd07b5194
7
- data.tar.gz: 3b4f1a99cf7397b170559177ceca023b3e7b22f5bfe632a0c77f26c62c815ef488fea667b781035025ae2283258a57c391185272fbe077ecefd84a51317e02be
6
+ metadata.gz: 4d57b3ce6c67e7bc25834d9109c290a86c64a56798c47ed23b3f01ca2ce3011ea90263cf3785fa6f76a3db00d14c2c9d04595e7fa1f35006f87cbaffebad823c
7
+ data.tar.gz: fbd33e894a99dadbe17b8dbc7569607871e829c161518e20f0f6eb7bcea537856a1a3a9d85edcd7b7a004be01ec1928b098bfac4f332913332cd059b329c7904
@@ -21,12 +21,14 @@ class String
21
21
  end
22
22
 
23
23
 
24
- # See {NRSER.constantize}
25
- def constantize
26
- NRSER.constantize self
24
+ def to_const
25
+ safe_constantize
27
26
  end
28
27
 
29
- alias_method :to_const, :constantize
28
+
29
+ def to_const!
30
+ constantize
31
+ end
30
32
 
31
33
 
32
34
  # @return [Pathname]
@@ -0,0 +1,23 @@
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
3
+
4
+ # Requirements
5
+ # =======================================================================
6
+
7
+ # Project / Package
8
+ # -----------------------------------------------------------------------
9
+
10
+ require_relative './nicer_error'
11
+
12
+
13
+ # Definitions
14
+ # =======================================================================
15
+
16
+ # General error for raising when something conflicts with something else -
17
+ # it's not the type or an argument, but something about the data or
18
+ # configuration just isn't ok.
19
+ #
20
+ module NRSER
21
+ class ConflictError < ::StandardError
22
+ include NRSER::NicerError
23
+ end; end # class NRSER::ConflictError
data/lib/nrser/errors.rb CHANGED
@@ -16,15 +16,11 @@ require_relative './errors/count_error'
16
16
  require_relative './errors/argument_error'
17
17
  require_relative './errors/type_error'
18
18
  require_relative './errors/abstract_method_error'
19
+ require_relative './errors/conflict_error'
19
20
 
20
21
 
21
22
  module NRSER
22
23
 
23
- # Indicates some piece of application state is in conflict with the attempted
24
- # operation.
25
- class ConflictError < StandardError; end
26
-
27
-
28
24
  # A wrapper error around a list of other errors.
29
25
  #
30
26
  class MultipleErrors < StandardError
@@ -233,59 +233,6 @@ module NRSER
233
233
 
234
234
  end # .smart_ellipsis
235
235
 
236
-
237
- # Get the constant identified by a string.
238
- #
239
- # @pure Return value depends only on parameters.
240
- #
241
- # @example
242
- #
243
- # SomeClass == NRSER.constantize(SomeClass.name)
244
- #
245
- # Lifted from ActiveSupport.
246
- #
247
- # @param [String] camel_cased_word
248
- # The constant's camel-cased, double-colon-separated "name",
249
- # like "NRSER::Types::Array".
250
- #
251
- # @return [Object]
252
- #
253
- # @raise [NameError]
254
- # When the name is not in CamelCase or is not initialized.
255
- #
256
- def self.constantize(camel_cased_word)
257
- names = camel_cased_word.split('::')
258
-
259
- # Trigger a built-in NameError exception including the ill-formed constant in the message.
260
- Object.const_get(camel_cased_word) if names.empty?
261
-
262
- # Remove the first blank element in case of '::ClassName' notation.
263
- names.shift if names.size > 1 && names.first.empty?
264
-
265
- names.inject(Object) do |constant, name|
266
- if constant == Object
267
- constant.const_get(name)
268
- else
269
- candidate = constant.const_get(name)
270
- next candidate if constant.const_defined?(name, false)
271
- next candidate unless Object.const_defined?(name)
272
-
273
- # Go down the ancestors to check if it is owned directly. The check
274
- # stops when we reach Object or the end of ancestors tree.
275
- constant = constant.ancestors.inject do |const, ancestor|
276
- break const if ancestor == Object
277
- break ancestor if ancestor.const_defined?(name, false)
278
- const
279
- end
280
-
281
- # owner is in Object, so raise
282
- constant.const_get(name, false)
283
- end
284
- end
285
- end # .constantize
286
-
287
- singleton_class.send :alias_method, :to_const, :constantize
288
-
289
236
  # @!endgroup String Functions
290
237
 
291
238
  end # module NRSER
@@ -98,7 +98,7 @@ class NRSER::Log::Formatters::Color < ::SemanticLogger::Formatters::Color
98
98
  # ======================================================================
99
99
 
100
100
  # Instantiate a new `ColorFormatter`.
101
- def initialize ap: {multiline: true, raw: true},
101
+ def initialize ap: {multiline: true }, # raw: true},
102
102
  color_map: self.class.default_color_map,
103
103
  time_format: ::SemanticLogger::Formatters::Base::TIME_FORMAT,
104
104
  log_host: false,
@@ -16,15 +16,26 @@ module NRSER::Log::Mixin
16
16
  # Methods to mix into the including class.
17
17
  #
18
18
  module ClassMethods
19
+
20
+ protected
21
+ # ========================================================================
22
+
23
+ def create_logger
24
+ NRSER::Log[self]
25
+ end
26
+
27
+ public # end protected ***************************************************
28
+
19
29
  # Returns [SemanticLogger::Logger] class level logger
20
30
  def logger
21
- @semantic_logger ||= NRSER::Log[ self ]
31
+ @semantic_logger ||= create_logger
22
32
  end
23
33
 
24
34
  # Replace instance class level logger
25
35
  def logger= logger
26
36
  @semantic_logger = logger
27
37
  end
38
+
28
39
  end
29
40
 
30
41
 
@@ -42,9 +53,52 @@ module NRSER::Log::Mixin
42
53
  # Instance Methods
43
54
  # ========================================================================
44
55
 
45
- # Returns [SemanticLogger::Logger] instance level logger
56
+ # Gets the {NRSER::Log:Logger} for use in the instance. This will be the
57
+ # class logger from {ClassMethods#logger} unless the instance has a
58
+ # `#create_logger` method.
59
+ #
60
+ # The `#create_logger` method is expected to return a {NRSER::Log::Logger}
61
+ # instance, which will be saved in the `@semantic_logger` instance variable
62
+ # for future use.
63
+ #
64
+ # That method does not need to return a different logger for every instance
65
+ # - if you just want to have a different logger for *all* instance with a
66
+ # different level or formatter or whatever, you can save it somewhere else
67
+ # and always return that same instance.
68
+ #
69
+ # If you are dealing with frozen instances make sure to call `#logger` before
70
+ # you freeze (likely in the constructor). If you don't want to save the
71
+ # logger at all, just override this method itself.
72
+ #
73
+ # This is a departure from {SemanticLogger::Loggable} that started because
74
+ # if the instance is frozen then attempting to set `@semantic_logger` will
75
+ # raise an error.
76
+ #
77
+ # I also started ending up with classes that wanted to individually
78
+ # configure their loggers, so it seemed like we could take out two birds
79
+ # with this stone.
80
+ #
81
+ # @return [SemanticLogger::Logger]
82
+ # Instance level logger, if {ClassMethods.instance_logger?},
83
+ # otherwise the class level logger from {ClassMethods#logger}.
84
+ #
46
85
  def logger
47
- @semantic_logger ||= self.class.logger
86
+ return @semantic_logger if @semantic_logger
87
+
88
+ if respond_to?( :create_logger, true )
89
+ @semantic_logger = begin
90
+ create_logger
91
+ rescue Exception => error
92
+ self.class.logger.warn \
93
+ "Error creating instance logger",
94
+ { instance: self.inspect },
95
+ error
96
+
97
+ self.class.logger
98
+ end
99
+ else
100
+ self.class.logger
101
+ end
48
102
  end
49
103
 
50
104
 
data/lib/nrser/log.rb CHANGED
@@ -88,7 +88,7 @@ module NRSER::Log
88
88
  # Class Methods
89
89
  # ========================================================================
90
90
 
91
- def self.[] subject
91
+ def self.logger_for subject
92
92
  # key = logger_type_and_name_from subject
93
93
  #
94
94
  # if @__loggers__.key? key
@@ -100,6 +100,9 @@ module NRSER::Log
100
100
  instance = NRSER::Log::Logger.new subject
101
101
  end
102
102
 
103
+ singleton_class.send :alias_method, :[], :logger_for
104
+
105
+
103
106
 
104
107
  # @!group Utility Class Methods
105
108
  # ------------------------------------------------------------------------
@@ -560,9 +563,16 @@ module NRSER::Log
560
563
  end
561
564
 
562
565
  if will_say_hi
566
+ loggable_dest = case dest
567
+ when Hash
568
+ dest.map { |k, v| [ k, v.to_s.truncate( 42 ) ] }.to_h
569
+ else
570
+ dest.to_s.truncate 42
571
+ end
572
+
563
573
  logger.info "Hi! Logging is setup",
564
574
  level: self.level,
565
- dest: dest,
575
+ dest: loggable_dest,
566
576
  sync: sync
567
577
  end
568
578
 
@@ -62,6 +62,15 @@ module NRSER::Props::ClassMethods
62
62
  end
63
63
 
64
64
 
65
+ def prop_for name_or_alias, *props_args
66
+ sym = name_or_alias.to_sym
67
+
68
+ props( *props_args ).each_value.find { |prop|
69
+ prop.name == sym || prop.aliases.include?( sym )
70
+ }
71
+ end
72
+
73
+
65
74
  def invariants *args, &block
66
75
  metadata.invariants *args, &block
67
76
  end
@@ -89,7 +98,6 @@ module NRSER::Props::ClassMethods
89
98
  #
90
99
  def from_data data
91
100
  values = {}
92
- props = self.props
93
101
 
94
102
  unless data.respond_to? :each_pair
95
103
  raise NRSER::ArgumentError.new \
@@ -107,7 +115,7 @@ module NRSER::Props::ClassMethods
107
115
  end
108
116
 
109
117
  if prop_key &&
110
- (prop = props[prop_key])
118
+ (prop = prop_for( prop_key, only_primary: true ))
111
119
  values[prop_key] = prop.value_from_data data_value
112
120
  end
113
121
  end
@@ -115,4 +123,23 @@ module NRSER::Props::ClassMethods
115
123
  self.new values
116
124
  end # #from_data
117
125
 
126
+
127
+ # Get an instance from a source.
128
+ #
129
+ # @experimental
130
+ #
131
+ # @param [self | String | Hash] source
132
+ # @return [self]
133
+ #
134
+ def self.from source
135
+ return source if source.is_a?( self )
136
+ return from_s( source ) if source.is_a?( String )
137
+ return from_data( source ) if source.respond_to?( :each_pair )
138
+ return from_data( source.to_h ) if source.respond_to?( :to_h )
139
+
140
+ raise NRSER::ArgumentError.new \
141
+ "Unable to load #{ self } from source",
142
+ source: source
143
+ end # .from
144
+
118
145
  end # module NRSER::Props::ClassMethods
@@ -95,9 +95,10 @@ module NRSER::Props::Immutable::Hash
95
95
 
96
96
  super_values = {}
97
97
 
98
- self.class.metadata.each_primary_prop_value_from( values ) { |prop, value|
99
- super_values[prop.name] = value
100
- }
98
+ self.class.metadata.
99
+ each_primary_prop_value_from( values ) { |prop, value|
100
+ super_values[prop.name] = value
101
+ }
101
102
 
102
103
  super super_values
103
104
 
@@ -38,6 +38,12 @@ class NRSER::Props::Metadata
38
38
  VARIABLE_NAME = :@__NRSER_metadata__
39
39
 
40
40
 
41
+ # Mixins
42
+ # ========================================================================
43
+
44
+ include NRSER::Log::Mixin
45
+
46
+
41
47
  # Class Methods
42
48
  # ======================================================================
43
49
 
@@ -217,6 +223,24 @@ class NRSER::Props::Metadata
217
223
  def each_primary_prop_value_from values, &block
218
224
  primary_props = props only_primary: true
219
225
 
226
+ props_by_names_and_aliases = {}
227
+ primary_props.each_value do |prop|
228
+ [prop.name, *prop.aliases].each do |sym|
229
+ if props_by_names_and_aliases.key? sym
230
+ other_prop = props_by_names_and_aliases[sym]
231
+
232
+ prop_sym_is = sym == prop.name ? 'name' : 'alias'
233
+ other_prop_sym_is = sym == other_prop.name ? 'name' : 'alias'
234
+
235
+ raise NRSER::ConflictError.new \
236
+ "Prop", prop.to_desc, prop_sym_is, sym.inspect,
237
+ "conflicts with", other_prop.to_desc, "of", other_prop_sym_is
238
+ end
239
+
240
+ props_by_names_and_aliases[sym] = prop
241
+ end
242
+ end
243
+
220
244
  # Normalize values to a `Hash<Symbol, VALUE>` so everything can deal with
221
245
  # one form. Default values will be set here as they're resolved and made
222
246
  # available to subsequent {Prop#default} calls.
@@ -237,9 +261,9 @@ class NRSER::Props::Metadata
237
261
  # If the `name` corresponds to a primary prop set it in the values by
238
262
  # name
239
263
  #
240
- # TODO Should check that the name is not already set?
241
- #
242
- values_by_name[name] = value if primary_props.key? name
264
+ if props_by_names_and_aliases.key? name
265
+ values_by_name[ props_by_names_and_aliases[name].name ] = value
266
+ end
243
267
  }
244
268
  elsif values.respond_to? :each_index
245
269
  indexed = []
@@ -263,6 +287,14 @@ class NRSER::Props::Metadata
263
287
  END
264
288
  end
265
289
 
290
+ # Way to noisy, even for trace
291
+ # logger.trace "Ready to start loading values",
292
+ # values: values,
293
+ # values_by_name: values_by_name,
294
+ # props_by_names_and_aliases: props_by_names_and_aliases.map { |k, v|
295
+ # [ k, v.to_desc ]
296
+ # }.to_h
297
+
266
298
  # Topological sort the primary props by their default dependencies.
267
299
  #
268
300
  NRSER::Graph::TSorter.new(
@@ -18,11 +18,11 @@ require 'nrser/refinements/types'
18
18
  using NRSER::Types
19
19
 
20
20
 
21
- # Declarations
21
+ # Namespace
22
22
  # =======================================================================
23
23
 
24
- module NRSER; end
25
- module NRSER::Props; end
24
+ module NRSER
25
+ module Props
26
26
 
27
27
 
28
28
  # Definitions
@@ -33,10 +33,17 @@ module NRSER::Props; end
33
33
  #
34
34
  # Props are immutable by design.
35
35
  #
36
- class NRSER::Props::Prop
36
+ class Prop
37
+
38
+ # Mixins
39
+ # ========================================================================
37
40
 
38
41
  include NRSER::Log::Mixin
39
42
 
43
+
44
+ # Attributes
45
+ # ========================================================================
46
+
40
47
  # The class the prop was defined in.
41
48
  #
42
49
  # @return [Class]
@@ -154,8 +161,17 @@ class NRSER::Props::Prop
154
161
  @to_data = to_data
155
162
  @from_data = from_data
156
163
 
157
- @reader = t.bool?.check! reader
158
- @writer = t.bool?.check! writer
164
+ @reader, @writer = [ reader, writer ].map do |value|
165
+ t.match value,
166
+ t.bool?,
167
+ value,
168
+
169
+ t.hash_( keys: t.sym, values: t.bool ),
170
+ :freeze.to_proc,
171
+
172
+ t.hash_( keys: t.label, values: t.bool ),
173
+ ->( hash ) { hash.map { |k, v| [ k.to_sym, v ] }.to_h.freeze }
174
+ end
159
175
 
160
176
  @aliases = t.array( t.sym ).check! aliases
161
177
 
@@ -201,7 +217,7 @@ class NRSER::Props::Prop
201
217
  defaults don't make any sense.
202
218
 
203
219
  Attempted to construct prop <%= name.inspect %> for class
204
- {<%= defined_in.name %>} with:
220
+ {<%= defined_in_name %>} with:
205
221
 
206
222
  default:
207
223
 
@@ -267,7 +283,7 @@ class NRSER::Props::Prop
267
283
  <%= default.pretty_inspect %>
268
284
 
269
285
  when constructing prop <%= name.inspect %>
270
- for class <%= defined_in.name %>
286
+ for class <%= defined_in_name %>
271
287
  END
272
288
  end
273
289
 
@@ -290,12 +306,27 @@ class NRSER::Props::Prop
290
306
  # Used by the {NRSER::Props::Props::ClassMethods.prop} "macro" method to
291
307
  # determine if it should create a reader method on the propertied class.
292
308
  #
309
+ # @param [Symbol] name
310
+ # The prop name or alias in question.
311
+ #
293
312
  # @return [Boolean]
294
313
  # `true` if a reader method should be created for the prop value.
295
314
  #
296
315
  def create_reader? name
297
- # If the options was explicitly provided then return that
298
- return @reader unless @reader.nil?
316
+ t.sym.check! name
317
+
318
+ # If the options was explicitly provided then use that
319
+ case @reader
320
+ when nil
321
+ # Fall through
322
+ when Hash
323
+ return @reader[name] if @reader.key? name
324
+ # else fall through
325
+ when true, false
326
+ return @reader
327
+ end
328
+
329
+ # return @reader unless @reader.nil?
299
330
 
300
331
  # Always create readers for primary props
301
332
  return true if primary?
@@ -321,7 +352,16 @@ class NRSER::Props::Prop
321
352
  # Always `false` for the moment.
322
353
  #
323
354
  def create_writer? name
324
- return @writer unless @writer.nil?
355
+ # If the options was explicitly provided then use that
356
+ case @writer
357
+ when nil
358
+ # Fall through
359
+ when Hash
360
+ return @writer[name] if @writer.key? name
361
+ # else fall through
362
+ when true, false
363
+ return @writer
364
+ end
325
365
 
326
366
  storage_immutable = defined_in.metadata.storage.try( :immutable? )
327
367
 
@@ -331,6 +371,12 @@ class NRSER::Props::Prop
331
371
  end # #create_writer?
332
372
 
333
373
 
374
+ def defined_in_name
375
+ return defined_in.safe_name if defined_in.respond_to?( :safe_name )
376
+ defined_in.to_s
377
+ end
378
+
379
+
334
380
  # Full name with class prop was defined in.
335
381
  #
336
382
  # @example
@@ -340,7 +386,7 @@ class NRSER::Props::Prop
340
386
  # @return [String]
341
387
  #
342
388
  def full_name
343
- "#{ defined_in.name }##{ name }"
389
+ "#{ defined_in_name }##{ name }"
344
390
  end # #full_name
345
391
 
346
392
 
@@ -616,7 +662,9 @@ class NRSER::Props::Prop
616
662
  # This {Prop} does not have any custom `from_data` instructions, which
617
663
  # means we must rely on the {#type} to covert *data* to a *value*.
618
664
  #
619
- if type.has_from_data?
665
+ if data.is_a?( String ) && type.has_from_s?
666
+ type.from_s data
667
+ elsif type.has_from_data?
620
668
  type.from_data data
621
669
  else
622
670
  data
@@ -660,11 +708,23 @@ class NRSER::Props::Prop
660
708
  end # #value_from_data
661
709
 
662
710
 
711
+ def to_desc
712
+ "#{ full_name }:#{ type }"
713
+ end
714
+
715
+
663
716
  # @return [String]
664
717
  # a short string describing the instance.
665
718
  #
666
719
  def to_s
667
- "#<#{ self.class.safe_name } #{ full_name }:#{ type }>"
720
+ "#<#{ self.class.safe_name } #{ to_desc }>"
668
721
  end # #to_s
669
722
 
670
- end # class NRSER::Props::Prop
723
+ end # class Prop
724
+
725
+
726
+ # /Namespace
727
+ # =======================================================================
728
+
729
+ end # module Props
730
+ end # module NRSER
@@ -4,6 +4,10 @@ module NRSER
4
4
  def t
5
5
  NRSER::Types
6
6
  end
7
+
8
+ def to_type
9
+ NRSER::Types.make self
10
+ end
7
11
  end
8
12
  end # module Types
9
13
  end # module NRSER
@@ -151,6 +151,9 @@ module NRSER::Types
151
151
  #
152
152
  # @return [NRSER::Types::Type]
153
153
  #
154
+ # @todo
155
+ # Make `list` into it's own looser interface for "array-like" object API.
156
+ #
154
157
  def_factory(
155
158
  :array,
156
159
  aliases: [:list],
@@ -191,9 +191,12 @@ module NRSER::Types
191
191
  # @return [NRSER::Types::Type]
192
192
  # Newly constructed hash type from `args`.
193
193
  #
194
+ # @todo
195
+ # Make `map` into it's own looser interface for "hash-like" object API.
196
+ #
194
197
  def_factory(
195
198
  :hash_type,
196
- aliases: [ :dict, :hash_ ]
199
+ aliases: [ :dict, :hash_, :map ]
197
200
  ) do |**kwds|
198
201
  if kwds.key?( :keys ) || kwds.key?( :values )
199
202
  HashOfType.new **kwds
@@ -85,6 +85,21 @@ module NRSER::Types
85
85
  end
86
86
 
87
87
 
88
+ # A relative path.
89
+ #
90
+ # @todo
91
+ # Quick addition, not sure if it's totally right with regard to tilde
92
+ # paths and such.
93
+ #
94
+ def_factory :rel_path do |name: 'RelPath', **options|
95
+ intersection \
96
+ path,
97
+ ~abs_path,
98
+ name: name,
99
+ **options
100
+ end
101
+
102
+
88
103
  # A {NRSER::Types.path} that is a directory.
89
104
  #
90
105
  # @param [Hash] **options
data/lib/nrser/version.rb CHANGED
@@ -18,7 +18,7 @@ module NRSER
18
18
  #
19
19
  # @return [String]
20
20
  #
21
- VERSION = '0.3.1'
21
+ VERSION = '0.3.2'
22
22
 
23
23
 
24
24
  module Version
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nrser
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - nrser
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-05-03 00:00:00.000000000 Z
11
+ date: 2018-05-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: hamster
@@ -256,6 +256,7 @@ files:
256
256
  - lib/nrser/errors/abstract_method_error.rb
257
257
  - lib/nrser/errors/argument_error.rb
258
258
  - lib/nrser/errors/attr_error.rb
259
+ - lib/nrser/errors/conflict_error.rb
259
260
  - lib/nrser/errors/count_error.rb
260
261
  - lib/nrser/errors/nicer_error.rb
261
262
  - lib/nrser/errors/type_error.rb