nrser 0.3.7 → 0.3.8

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: ea96a298163ec6b20a0437bc7ab7c8ea9200fd99
4
- data.tar.gz: c6aabc018e890bfa791e20925b2c32240c4110d7
3
+ metadata.gz: 20a9f5822833e3797ebf2ec2ba0b6e430ad7346e
4
+ data.tar.gz: 0dc5e6c87d30f0d9ed99692b33da84a4f2584db9
5
5
  SHA512:
6
- metadata.gz: 29d05d08cc6d63ee707ad4ce1bf34b4b148a132ee669749ad1a01eb392ba1ef6d842c1be240cbf0ec2d514e3acd320c70e2f84e86376d93ad54a688ffa428244
7
- data.tar.gz: 4dc97cdc270fc79692b1a7ffcba3c569ae3649247f78e16b128603933c40ebb05c925fe934b53a5c082f23788cde3444ba4cf7f082143b27274c53104647cac5
6
+ metadata.gz: 374129784c79fe2897c078beed6e4d7c168e9b2e79027bf293df15403eac73a505176db6238f2c9b14ba8d2ecbda399e61c5f2a57cce4b8ec79a0c7a12ec031e
7
+ data.tar.gz: ae5a9bb34f77b6d35976fbed02fa85b8267a34b9cfb0a0ec0b4db6b39bae1d38ed08c3c994f27439f437580ebc9023c6d23c19ef827b58691a5aca0969f4e17a
@@ -92,6 +92,16 @@ class Pathname
92
92
  end
93
93
 
94
94
 
95
+ # Shortcut to call {#to_rel} with `dot_slash=true`.
96
+ #
97
+ # @param base_dir: (see .to_rel)
98
+ # @return (see .to_rel)
99
+ #
100
+ def to_dot_rel **kwds
101
+ to_rel **kwds, dot_slash: true
102
+ end # #to_dot_rel
103
+
104
+
95
105
  # Just a quick cut for `.to_rel.to_s`, since I seem to use that sort of form
96
106
  # a lot.
97
107
  #
@@ -99,8 +109,18 @@ class Pathname
99
109
  #
100
110
  # @return [String]
101
111
  #
102
- def to_rel_s *args
103
- to_rel( *args ).to_s
112
+ def to_rel_s **kwds
113
+ to_rel( **kwds ).to_s
114
+ end
115
+
116
+
117
+ # Shortcut to call {#to_rel_s} with `dot_slash=true`.
118
+ #
119
+ # @param base_dir: (see .to_rel_s)
120
+ # @return (see .to_rel_s)
121
+ #
122
+ def to_dot_rel_s **kwds
123
+ to_rel_s( **kwds, dot_slash: true ).to_s
104
124
  end
105
125
 
106
126
  end # class Pathname
@@ -1,10 +1,27 @@
1
- module NRSER::Ext; end
1
+ # frozen_string_literal: true
2
+ # encoding: UTF-8
3
+
4
+
5
+ # Requirements
6
+ # ========================================================================
7
+
8
+ # Project / Package
9
+ # ------------------------------------------------------------------------
10
+
11
+ require 'nrser/functions/tree'
12
+
13
+
14
+ # Namespace
15
+ # ========================================================================
16
+
17
+ module NRSER
18
+ module Ext
2
19
 
3
20
 
4
21
  # Instance methods that are refined in to the Ruby built-ins that we consider
5
22
  # trees: {Array}, {Hash} and {OpenStruct}.
6
23
  #
7
- module NRSER::Ext::Tree
24
+ module Tree
8
25
 
9
26
  # Sends `self` to {NRSER.leaves}.
10
27
  def leaves
@@ -39,4 +56,11 @@ module NRSER::Ext::Tree
39
56
  NRSER.map_tree self, **options, &block
40
57
  end
41
58
 
42
- end # module NRSER::Ext::Tree
59
+ end # module Tree
60
+
61
+
62
+ # /Namespace
63
+ # ========================================================================
64
+
65
+ end # module Ext
66
+ end # module NRSER
@@ -0,0 +1,53 @@
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
3
+
4
+ # Requirements
5
+ # =======================================================================
6
+
7
+ # Deps
8
+ # -----------------------------------------------------------------------
9
+
10
+ require 'hamster'
11
+
12
+ require 'nrser/ext/tree'
13
+
14
+
15
+ # Namespace
16
+ # =======================================================================
17
+
18
+ module Hamster
19
+
20
+
21
+ # Definitions
22
+ # =======================================================================
23
+
24
+ class Hash
25
+
26
+ include NRSER::Ext::Tree
27
+
28
+ # Instance Methods
29
+ # ========================================================================
30
+
31
+ def to_mutable
32
+ each_with_object( {} ) { |(key, value), hash|
33
+ hash[ Hamster.to_mutable key ] = Hamster.to_mutable value
34
+ }
35
+ end
36
+
37
+
38
+ def as_json options = nil
39
+ to_h.as_json options
40
+ end
41
+
42
+
43
+ def to_yaml *args, &block
44
+ to_mutable.to_yaml *args, &block
45
+ end
46
+
47
+ end # class Hash
48
+
49
+
50
+ # /Namespace
51
+ # =======================================================================
52
+
53
+ end # module Hamster
@@ -0,0 +1,69 @@
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
3
+
4
+ # Requirements
5
+ # =======================================================================
6
+
7
+ # Stdlib
8
+ # ----------------------------------------------------------------------------
9
+
10
+ require 'set'
11
+
12
+ # Deps
13
+ # -----------------------------------------------------------------------
14
+
15
+ require 'hamster'
16
+
17
+ require 'nrser/ext/tree'
18
+
19
+
20
+ # Namespace
21
+ # =======================================================================
22
+
23
+ module Hamster
24
+
25
+
26
+ # Definitions
27
+ # =======================================================================
28
+
29
+ class Set
30
+
31
+ # Instance Methods
32
+ # ========================================================================
33
+
34
+ def to_mutable
35
+ each_with_object( ::Set[] ) { |member, set|
36
+ set << Hamster.to_mutable( member )
37
+ }
38
+ end
39
+
40
+
41
+ def to_mutable_array
42
+ each_with_object( [] ) { |member, array|
43
+ array << Hamster.to_mutable( member )
44
+ }
45
+ end
46
+
47
+
48
+ def to_h
49
+ each_with_object( {} ) { |member, hash| hash[member] = true }
50
+ end
51
+
52
+
53
+ def as_json options = nil
54
+ to_mutable_array.to_json options
55
+ # { '$set' => to_h.as_json( options ) }
56
+ end
57
+
58
+
59
+ def to_yaml *args, &block
60
+ to_mutable.to_yaml *args, &block
61
+ end
62
+
63
+ end # class Hash
64
+
65
+
66
+ # /Namespace
67
+ # =======================================================================
68
+
69
+ end # module Hamster
@@ -0,0 +1,69 @@
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
3
+
4
+ # Requirements
5
+ # =======================================================================
6
+
7
+ # Stdlib
8
+ # ----------------------------------------------------------------------------
9
+
10
+ require 'set'
11
+
12
+ # Deps
13
+ # -----------------------------------------------------------------------
14
+
15
+ require 'hamster'
16
+
17
+ require 'nrser/ext/tree'
18
+
19
+
20
+ # Namespace
21
+ # =======================================================================
22
+
23
+ module Hamster
24
+
25
+
26
+ # Definitions
27
+ # =======================================================================
28
+
29
+ class SortedSet
30
+
31
+ # Instance Methods
32
+ # ========================================================================
33
+
34
+ def to_mutable
35
+ each_with_object( ::SortedSet[] ) { |member, set|
36
+ set << Hamster.to_mutable( member )
37
+ }
38
+ end
39
+
40
+
41
+ def to_mutable_array
42
+ each_with_object( [] ) { |member, array|
43
+ array << Hamster.to_mutable( member )
44
+ }
45
+ end
46
+
47
+
48
+ def to_h
49
+ each_with_object( {} ) { |member, hash| hash[member] = true }
50
+ end
51
+
52
+
53
+ def as_json options = nil
54
+ to_mutable_array.to_json options
55
+ # { '$set' => to_h.as_json( options ) }
56
+ end
57
+
58
+
59
+ def to_yaml *args, &block
60
+ to_mutable.to_yaml *args, &block
61
+ end
62
+
63
+ end # class Hash
64
+
65
+
66
+ # /Namespace
67
+ # =======================================================================
68
+
69
+ end # module Hamster
@@ -0,0 +1,53 @@
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
3
+
4
+ # Requirements
5
+ # =======================================================================
6
+
7
+ # Deps
8
+ # -----------------------------------------------------------------------
9
+
10
+ require 'hamster'
11
+
12
+ require 'nrser/ext/tree'
13
+
14
+
15
+ # Namespace
16
+ # =======================================================================
17
+
18
+ module Hamster
19
+
20
+
21
+ # Definitions
22
+ # =======================================================================
23
+
24
+ class Vector
25
+
26
+ include NRSER::Ext::Tree
27
+
28
+ # Instance Methods
29
+ # ========================================================================
30
+
31
+ def to_mutable
32
+ each_with_object( [] ) { |entry, array|
33
+ array << Hamster.to_mutable( entry )
34
+ }
35
+ end
36
+
37
+
38
+ def as_json options = nil
39
+ to_mutable.as_json options
40
+ end
41
+
42
+
43
+ def to_yaml *args, &block
44
+ to_mutable.to_yaml *args, &block
45
+ end
46
+
47
+ end # class Hash
48
+
49
+
50
+ # /Namespace
51
+ # =======================================================================
52
+
53
+ end # module Hamster
@@ -0,0 +1,36 @@
1
+ require 'set'
2
+
3
+ require 'hamster'
4
+ require_relative './hamster/hash'
5
+ require_relative './hamster/vector'
6
+ require_relative './hamster/set'
7
+ require_relative './hamster/sorted_set'
8
+
9
+ module Hamster
10
+ # def self.regrow each_pair: ::Hash, each_index: ::Array, each:
11
+
12
+ def self.to_mutable obj
13
+ if obj.respond_to? :to_mutable
14
+ obj.to_mutable
15
+
16
+ elsif ::Array === obj
17
+ obj.map { |e| to_mutable e }
18
+
19
+ elsif ::Hash === obj
20
+ obj.each_with_object( {} ) { |(k, v), h|
21
+ h[ to_mutable k ] = to_mutable v
22
+ }
23
+
24
+ elsif ::SortedSet === obj
25
+ ::SortedSet.new obj.map { |m| to_mutable m }
26
+
27
+ elsif ::Set === obj
28
+ ::Set.new obj.map { |m| to_mutable m }
29
+
30
+ else
31
+ obj
32
+
33
+ end
34
+ end # .to_mutable
35
+
36
+ end
@@ -0,0 +1,233 @@
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
3
+
4
+ # Requirements
5
+ # =======================================================================
6
+
7
+ # Stdlib
8
+ # -----------------------------------------------------------------------
9
+ require 'set'
10
+
11
+ # Deps
12
+ # -----------------------------------------------------------------------
13
+ require 'hamster'
14
+
15
+ # Project / Package
16
+ # -----------------------------------------------------------------------
17
+ require 'nrser/errors/type_error'
18
+ require 'nrser/props/immutable/hash'
19
+ require 'nrser/props/immutable/vector'
20
+
21
+ require 'nrser/refinements/types'
22
+ using NRSER::Types
23
+
24
+
25
+ # Definitions
26
+ # =======================================================================
27
+
28
+ # Sick of typing "Hamster::Hash"...
29
+ #
30
+ # Experimental Hamster sugary sweet builder shortcut things.
31
+ #
32
+ module I8
33
+
34
+ # Easy way to get the class names shorter..?
35
+ class Vector < Hamster::Vector; end
36
+ class Hash < Hamster::Hash; end
37
+ class Set < Hamster::Set; end
38
+ class SortedSet < Hamster::SortedSet; end
39
+ # class List < Hamster::List; end # Not a class! Ugh...
40
+
41
+
42
+ module Struct
43
+
44
+ def self.check_new_args! vector_prop_defs, hash_prop_defs
45
+
46
+ unless (vector_prop_defs.empty? && !hash_prop_defs.empty?) ||
47
+ (!vector_prop_defs.empty? && hash_prop_defs.empty?)
48
+
49
+ raise NRSER::ArgumentError.new \
50
+ "Exactly one of *args or **kwds must be empty",
51
+
52
+ args: vector_prop_defs,
53
+
54
+ kwds: hash_prop_defs,
55
+
56
+ details: -> {%{
57
+ {I8::Struct.define} proxies to either
58
+
59
+ 1. {I8::Struct::Vector.define}
60
+ 2. {I8::Struct::Hash.define}
61
+
62
+ depending on *where* the property definitions are passed:
63
+
64
+ 1. Positionally in `*args` -> {I8::Struct::Vector.new}
65
+ 2. By name in `**kwds` -> {I8::Struct::Hash.new}
66
+
67
+ Examples:
68
+
69
+ 1. Create a Point struct backed by an {I8::Vector}:
70
+
71
+ Point = I8::Struct.define [x: t.int], [y: t.int]
72
+
73
+ 2. Create a Point struct backed by an {I8::Hash}:
74
+
75
+ Point = I8::Struct.define x: t.int, y: t.int
76
+
77
+ }}
78
+
79
+ end # unless vector_prop_defs.empty? XOR hash_prop_defs.empty?
80
+
81
+ end # .check_new_args!
82
+
83
+ private_class_method :check_new_args!
84
+
85
+
86
+ def self.define *vector_prop_defs, **hash_prop_defs, &body
87
+ check_new_args! vector_prop_defs, hash_prop_defs
88
+
89
+ if !vector_prop_defs.empty?
90
+ raise "not implemented"
91
+ # I8::Struct::Vector.new
92
+ else
93
+ I8::Struct::Hash.new **hash_prop_defs, &body
94
+ end
95
+ end
96
+
97
+ singleton_class.send :alias_method, :new, :define
98
+
99
+
100
+ end # module Struct
101
+
102
+
103
+ class Struct::Hash < I8::Hash
104
+ include I8::Struct
105
+ include NRSER::Props::Immutable::Hash
106
+
107
+ def self.define **prop_defs, &body
108
+ Class.new( I8::Struct::Hash ) do
109
+ prop_defs.each do |name, settings|
110
+ kwds = t.match settings,
111
+ t.type, ->( type ) {{ type: type }},
112
+ t.hash_, settings
113
+
114
+ prop name, **kwds
115
+ end
116
+
117
+ class_exec &body if body
118
+ end
119
+ end
120
+
121
+ def self.new *args, **kwds, &block
122
+ if self == I8::Struct::Hash
123
+ define *args, **kwds, &block
124
+ else
125
+ # See NOTE in {I8::Struct::Vector.new}
126
+ if kwds.empty?
127
+ super( *args, &block )
128
+ else
129
+ super( *args, **kwds, &block )
130
+ end
131
+ end
132
+ end
133
+ end
134
+
135
+
136
+ class Struct::Vector < I8::Vector
137
+ include I8::Struct
138
+ include NRSER::Props::Immutable::Vector
139
+
140
+ def self.define *prop_defs, &body
141
+ # Unwrap `[name: type]` format
142
+ prop_defs.map! { |prop_def|
143
+ if ::Array === prop_def &&
144
+ prop_def.length == 1 &&
145
+ ::Hash === prop_def[0]
146
+ prop_def[0]
147
+ else
148
+ prop_def
149
+ end
150
+ }
151
+
152
+ # Check we have a list of pairs with label keys
153
+ t.array( t.pair( key: t.label ) ).check! prop_defs
154
+
155
+ Class.new( I8::Struct::Vector ) do
156
+ prop_defs.each_with_index do |pair, index|
157
+ name, settings = pair.first
158
+
159
+ kwds = t.match settings,
160
+ t.type, ->( type ) {{ type: type }},
161
+ t.hash_, settings
162
+
163
+ prop name, **kwds, index: index
164
+ end
165
+
166
+ class_exec &body if body
167
+ end
168
+ end
169
+
170
+
171
+ def self.new *args, **kwds, &block
172
+ if self == I8::Struct::Vector
173
+ unless kwds.empty?
174
+ raise NRSER::ArgumentError.new \
175
+ "Can not supply keyword args",
176
+ args: args,
177
+ kwds: kwds
178
+ end
179
+
180
+ define *args, &block
181
+ else
182
+ # NOTE This is... weird. Just doing the normal
183
+ #
184
+ # super( *args, **kwds, &block )
185
+ #
186
+ # results in `*args` becoming `[*args, {}]` up the super chain
187
+ # when `kwds` is empty.
188
+ #
189
+ # I can't say I can understand it, but I seem to be able to fix
190
+ # it.
191
+ #
192
+ if kwds.empty?
193
+ super( *args, &block )
194
+ else
195
+ super( *args, **kwds, &block )
196
+ end
197
+ end
198
+ end
199
+
200
+ end # class Struct::Vector
201
+
202
+
203
+ def self.[] value
204
+ case value
205
+ when Hamster::Hash,
206
+ Hamster::Vector,
207
+ Hamster::Set,
208
+ Hamster::SortedSet,
209
+ Hamster::List
210
+ value
211
+ when ::Hash
212
+ I8::Hash[value]
213
+ when ::Array
214
+ I8::Vector.new value
215
+ when ::Set
216
+ I8::Set.new value
217
+ when ::SortedSet
218
+ I8::SortedSet.new value
219
+ else
220
+ raise NRSER::TypeError.new \
221
+ "Value must be Hash, Array, Set or SortedSet",
222
+ found: value
223
+ end
224
+ end # .[]
225
+
226
+ end # module I8
227
+
228
+
229
+ # Method proxy to {I8.[]} allowing for different syntaxes.
230
+ #
231
+ def I8 value = nil
232
+ I8[ value || yield ]
233
+ end
@@ -0,0 +1,82 @@
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
3
+
4
+ # Requirements
5
+ # =======================================================================
6
+
7
+ # Deps
8
+ # -----------------------------------------------------------------------
9
+
10
+ # Need {SemanticLogger::LEVELS}
11
+ require 'semantic_logger'
12
+
13
+
14
+ # Refinements
15
+ # =======================================================================
16
+
17
+ require 'nrser/refinements/types'
18
+ using NRSER::Types
19
+
20
+
21
+ # Namespace
22
+ # =======================================================================
23
+
24
+ module NRSER
25
+ module Log
26
+
27
+
28
+ # Definitions
29
+ # =======================================================================
30
+
31
+ # Types for logging type things.
32
+ #
33
+ # @note
34
+ # This module is **NOT** required when loading {NRSER::Log}, and it **NEVER**
35
+ # should be! It is here for *other* gems and apps that depend on {NRSER}
36
+ # to use.
37
+ #
38
+ # Core logging should have the absolute minimal dependencies, because it's
39
+ # pretty much always going to be loaded and nothing it depends on can use
40
+ # it when loading up.
41
+ #
42
+ module Types
43
+ extend NRSER::Types::Factory
44
+
45
+ def_factory :level do |
46
+ name: 'LogLevel',
47
+ from_s: ->( string ) { string.to_sym },
48
+ **options
49
+ |
50
+ t.in SemanticLogger::LEVELS, from_s: from_s, name: name, **options
51
+ end
52
+
53
+
54
+ def_factory :stdio do |
55
+ name: 'StdIO',
56
+
57
+ from_s: ->( string ) {
58
+ case string
59
+ when '$stdout'
60
+ $stdout
61
+ when '$stderr'
62
+ $stderr
63
+ when 'STDOUT'
64
+ STDOUT
65
+ when 'STDERR'
66
+ STDERR
67
+ end
68
+ },
69
+
70
+ **options
71
+ |
72
+ t.is_a IO, name: name, from_s: from_s, **options
73
+ end
74
+
75
+ end # module Types
76
+
77
+
78
+ # /Namespace
79
+ # =======================================================================
80
+
81
+ end # module Log
82
+ end # module NRSER
data/lib/nrser/log.rb CHANGED
@@ -19,6 +19,8 @@ require "concurrent/map"
19
19
  # Project / Package
20
20
  # -----------------------------------------------------------------------
21
21
 
22
+ # Using {NRSER.truthy?} for ENV var values.
23
+ require 'nrser/functions/object/truthy'
22
24
 
23
25
  # Definitions
24
26
  # =======================================================================
@@ -38,10 +40,6 @@ module NRSER::Log
38
40
  require_relative './log/appender'
39
41
 
40
42
 
41
- # Constants
42
- # ========================================================================
43
-
44
-
45
43
  # Mixins
46
44
  # ========================================================================
47
45
 
@@ -359,14 +357,14 @@ module NRSER::Log
359
357
  # @param (see .setup!)
360
358
  # @return (see .setup!)
361
359
  #
362
- def self.setup_for_CLI! dest: $stderr,
360
+ def self.setup_for_cli! dest: $stderr,
363
361
  sync: true,
364
362
  **kwds
365
363
  setup! dest: dest, sync: sync, **kwds
366
- end # .setup_for_CLI!
364
+ end # .setup_for_cli!
367
365
 
368
- # Old name
369
- singleton_class.send :alias_method, :setup_for_cli!, :setup_for_CLI!
366
+ # Was the new name, then realized it was dumb and switched back :D
367
+ singleton_class.send :alias_method, :setup_for_CLI!, :setup_for_cli!
370
368
 
371
369
 
372
370
  # Call {.setup!} with some default keywords that are nice for interactive
@@ -696,6 +694,9 @@ module NRSER::Log
696
694
  old_appender = @appender
697
695
 
698
696
  @appender = case dest
697
+ when false
698
+ # Used to remove the appender and set {.appender} to `nil`.
699
+ nil
699
700
  when SemanticLogger::Subscriber, Hash
700
701
  # Can be handled directly
701
702
  SemanticLogger.add_appender dest
@@ -18,7 +18,7 @@ module NRSER::RSpex::ExampleGroup
18
18
  # @param [Array] *args
19
19
  # Arguments to call `subject` with to produce the new subject.
20
20
  #
21
- # @param [#call] &block
21
+ # @param [#call] &body
22
22
  # Block to execute in the context of the example group after refining
23
23
  # the subject.
24
24
  #
@@ -34,4 +34,25 @@ module NRSER::RSpex::ExampleGroup
34
34
  # Short / old name
35
35
  alias_method :called_with, :describe_called_with
36
36
 
37
+
38
+ # Version of {#describe_called_with} for when you have no arguments.
39
+ #
40
+ # @param [#call] &body
41
+ # Block to execute in the context of the example group after refining
42
+ # the subject.
43
+ #
44
+ # @return [void]
45
+ #
46
+ def describe_called &body
47
+ describe_x Args(),
48
+ type: :called_with,
49
+ subject_block: -> { super().call },
50
+ &body
51
+ end
52
+
53
+ alias_method :called, :describe_called
54
+ alias_method :when_called, :describe_called
55
+
56
+
57
+
37
58
  end # module NRSER::RSpex::ExampleGroup
@@ -2,13 +2,13 @@
2
2
 
3
3
  module NRSER::RSpex::ExampleGroup
4
4
 
5
- # @todo Document describe_instance method.
5
+ # Describe an instance of the described class by providing arguments for
6
+ # it's construction.
6
7
  #
7
- # @param [type] arg_name
8
- # @todo Add name param description.
8
+ # @param [Array] *constructor_args
9
+ # Arguments to pass to `.new` on {#described_class} to create instances.
9
10
  #
10
- # @return [return_type]
11
- # @todo Document return value.
11
+ # @return [void]
12
12
  #
13
13
  def describe_instance *constructor_args, &body
14
14
  describe_x ".new", Args(*constructor_args),
@@ -119,7 +119,7 @@ module NRSER::Types
119
119
  if type.has_from_data?
120
120
  begin
121
121
  return check!( type.from_data data )
122
- rescue Exception => error
122
+ rescue StandardError => error
123
123
  errors << error
124
124
  end
125
125
  end
@@ -78,7 +78,9 @@ module NRSER::Types::Factory
78
78
  maybe_options = options.slice *maybe_option_keys
79
79
  factory_options = options.except *maybe_option_keys
80
80
 
81
- maybe public_send( name, *args, **factory_options ), **maybe_options
81
+ NRSER::Types.maybe \
82
+ public_send( name, *args, **factory_options ),
83
+ **maybe_options
82
84
  end
83
85
 
84
86
  aliases.each do |alias_name|
@@ -89,4 +89,10 @@ module NRSER::Types
89
89
  def_factory :is_a do |mod, **options|
90
90
  IsA.new mod, **options
91
91
  end
92
+
93
+
94
+ def_factory :type do |**options|
95
+ is_a NRSER::Types::Type
96
+ end
97
+
92
98
  end # NRSER::Types
@@ -1,18 +1,91 @@
1
- require_relative './combinators'
2
- require_relative './nil'
1
+ # Requirements
2
+ # ========================================================================
3
3
 
4
- module NRSER::Types
5
-
6
- # Type satisfied by `nil` or the parametrized type.
4
+ # Project / Package
5
+ # ------------------------------------------------------------------------
6
+
7
+ require_relative './is_a'
8
+
9
+
10
+ # Namespace
11
+ # ========================================================================
12
+
13
+ module NRSER
14
+ module Types
15
+
16
+
17
+ # Definitions
18
+ # ========================================================================
19
+
20
+ class Maybe < Type
21
+
22
+ # Attributes
23
+ # ========================================================================
24
+
25
+ # The type of all members besides `nil`.
7
26
  #
8
- def_factory(
9
- :maybe,
10
- ) do |type, **options|
11
- union \
12
- self.nil,
13
- type,
14
- name: (options[:name] || "#{ type.name }?"),
15
- **options
27
+ # @return [Type]
28
+ #
29
+ attr_reader :type
30
+
31
+
32
+ # Constructor
33
+ # ======================================================================
34
+
35
+ # Instantiate a new `NRSER::Types::Maybe`.
36
+ def initialize type, **options
37
+ super **options
38
+ @type = NRSER::Types.make type
39
+ end # #initialize
40
+
41
+
42
+ # Instance Methods
43
+ # ========================================================================
44
+
45
+ def test? value
46
+ value.nil? || @type.test?( value )
16
47
  end
17
48
 
18
- end # NRSER::Types
49
+
50
+ def explain
51
+ "#{ @type.name }?"
52
+ end
53
+
54
+
55
+ def has_from_s?
56
+ !@from_s.nil? || type.has_from_s?
57
+ end
58
+
59
+
60
+ def custom_from_s string
61
+ type.from_s string
62
+ end
63
+
64
+ end # class Maybe
65
+
66
+
67
+ # @!group Type Factory Functions
68
+ # ----------------------------------------------------------------------------
69
+
70
+ # @!method
71
+ # Type satisfied by `nil` or the parametrized type.
72
+ #
73
+ # @param [Type] type
74
+ # The type values must be if they are not `nil`.
75
+ #
76
+ # @param **options (see Type.initialize)
77
+ #
78
+ # @return [Type]
79
+ #
80
+ def_factory :maybe do |type, **options|
81
+ Maybe.new type, **options
82
+ end
83
+
84
+ # @!endgroup Type Factory Functions # ****************************************
85
+
86
+
87
+ # /Namespace
88
+ # ========================================================================
89
+
90
+ end # module Types
91
+ end # module NRSER
@@ -44,11 +44,12 @@ module NRSER::Types
44
44
  end
45
45
 
46
46
 
47
- # A path is a non-empty {String} or {Pathname}.
48
- #
49
- # @param **options see NRSER::Types::Type#initialize
50
- #
51
- # @return [NRSER::Types::Type]
47
+ # @!method
48
+ # A path is a non-empty {String} or {Pathname}.
49
+ #
50
+ # @param **options see NRSER::Types::Type#initialize
51
+ #
52
+ # @return [NRSER::Types::Type]
52
53
  #
53
54
  def_factory :path do |name: 'Path', **options|
54
55
  one_of \
data/lib/nrser/version.rb CHANGED
@@ -18,7 +18,7 @@ module NRSER
18
18
  #
19
19
  # @return [String]
20
20
  #
21
- VERSION = '0.3.7'
21
+ VERSION = '0.3.8'
22
22
 
23
23
 
24
24
  module Version
data/lib/nrser.rb CHANGED
@@ -69,6 +69,8 @@ require_relative './nrser/core_ext/binding'
69
69
  # Then everything else...
70
70
  require_relative './nrser/char'
71
71
  require_relative './nrser/errors'
72
+ require 'nrser/gem_ext/hamster'
73
+
72
74
  require_relative './nrser/no_arg'
73
75
  require_relative './nrser/message'
74
76
  require_relative './nrser/collection'
@@ -0,0 +1,114 @@
1
+ require 'nrser/labs/i8'
2
+
3
+ describe_spec_file(
4
+ spec_path: __FILE__,
5
+ module: Hamster,
6
+ ) do
7
+
8
+ describe_setup %{
9
+ Converting Hamsters to regular structures with their `#to_mutable`
10
+ }.squish do
11
+
12
+ it %{ gets immutable objects nested inside mutable ones } do
13
+
14
+ # Because `I8({ x: 1 }) == { x: 1 }` (which is usually probably very nice
15
+ # to have) we have to do more than just compare with `==`.
16
+ #
17
+ # I *think* this accomplishes what we want...
18
+ #
19
+ def class_match actual, expected
20
+ return false unless actual == expected &&
21
+ actual.class == expected.class &&
22
+ actual.eql?( expected ) # This alone is prob
23
+ # enough...
24
+
25
+ case expected
26
+ when ::Hash, ::Array
27
+ expected.each_branch do |key, expected_value|
28
+ return false unless class_match( expected_value, actual[key] )
29
+ end
30
+ when ::Set
31
+ expected.each do |expected_value|
32
+ return false unless actual.include?( expected_value )
33
+ end
34
+ end
35
+
36
+ true
37
+ end
38
+
39
+ expect(
40
+ class_match(
41
+ I8({ x: { y: I8({ z: 1 }) } }).to_mutable,
42
+ { x: { y: { z: 1 } } }
43
+ )
44
+ ).to be true
45
+
46
+ expect(
47
+ class_match(
48
+ I8({ x: { y: I8({ z: 1 }) } }).to_mutable,
49
+ { x: { y: { z: 1 } } },
50
+ )
51
+ ).to be true
52
+
53
+ expect(
54
+ class_match(
55
+ I8({ items: [ I8({ id: 1 }), I8({ id: 2 }) ] }).to_mutable,
56
+ { items: [ { id: 1 }, {id: 2 } ] },
57
+ )
58
+ ).to be true
59
+
60
+ expect(
61
+ class_match(
62
+ I8({ items: Set[ I8({ id: 1 }), I8({ id: 2 }) ] }).to_mutable,
63
+ { items: Set[ { id: 1 }, {id: 2 } ] },
64
+ )
65
+ ).to be true
66
+ end
67
+
68
+ end # setup
69
+
70
+
71
+ describe_class Hamster::Hash do
72
+ describe_instance x: 1, y: 2, z: 3 do
73
+ describe_method :to_mutable do
74
+ when_called do
75
+ it { is_expected.to be_a( ::Hash ).and eq( {x: 1, y: 2, z: 3} ) }
76
+ end
77
+ end
78
+ end
79
+ end
80
+
81
+
82
+ describe_class Hamster::Vector do
83
+ describe_instance [1, 2, 3] do
84
+ describe_method :to_mutable do
85
+ when_called do
86
+ it { is_expected.to be_a( ::Array ).and eq [1, 2, 3] }
87
+ end
88
+ end
89
+ end
90
+ end
91
+
92
+
93
+ describe_class Hamster::Set do
94
+ describe_instance [1, 2, 3] do
95
+ describe_instance_method :to_mutable do
96
+ when_called {
97
+ it { is_expected.to be_a( ::Set ).and eq ::Set[1, 2, 3] }
98
+ }
99
+ end
100
+ end
101
+ end
102
+
103
+
104
+ describe_class Hamster::SortedSet do
105
+ describe_instance [1, 2, 3] do
106
+ describe_instance_method :to_mutable do
107
+ when_called {
108
+ it { is_expected.to be_a( ::SortedSet ).and eq ::SortedSet[1, 2, 3] }
109
+ }
110
+ end
111
+ end
112
+ end
113
+
114
+ end # Spec File Description
@@ -57,7 +57,7 @@ describe NRSER::Props::Immutable::Vector do
57
57
  # defined classes.
58
58
  def self.name; 'Point2DInt'; end
59
59
 
60
- # It's vital that we include the `key:` keyword argument, and that the
60
+ # It's vital that we include the `index:` keyword argument, and that the
61
61
  # values are non-negative integer indexes for the vector.
62
62
  prop :x, type: t.int, index: 0
63
63
  prop :y, type: t.int, index: 1
data/spec/spec_helper.rb CHANGED
@@ -32,6 +32,13 @@ RSpec.configure do |config|
32
32
 
33
33
  config.example_status_persistence_file_path = \
34
34
  NRSER::ROOT / 'tmp' / ".rspec_status"
35
+
36
+ # This allows you to limit a spec run to individual examples or groups
37
+ # you care about by tagging them with `:focus` metadata. When nothing
38
+ # is tagged with `:focus`, all examples get run. RSpec also provides
39
+ # aliases for `it`, `describe`, and `context` that include `:focus`
40
+ # metadata: `fit`, `fdescribe` and `fcontext`, respectively.
41
+ config.filter_run_when_matching :focus
35
42
  end
36
43
 
37
44
 
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.7
4
+ version: 0.3.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - nrser
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-06-23 00:00:00.000000000 Z
11
+ date: 2018-07-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: hamster
@@ -317,10 +317,16 @@ files:
317
317
  - lib/nrser/functions/tree/map_leaves.rb
318
318
  - lib/nrser/functions/tree/map_tree.rb
319
319
  - lib/nrser/functions/tree/transform.rb
320
+ - lib/nrser/gem_ext/hamster.rb
321
+ - lib/nrser/gem_ext/hamster/hash.rb
322
+ - lib/nrser/gem_ext/hamster/set.rb
323
+ - lib/nrser/gem_ext/hamster/sorted_set.rb
324
+ - lib/nrser/gem_ext/hamster/vector.rb
320
325
  - lib/nrser/graph/tsorter.rb
321
326
  - lib/nrser/labs.rb
322
327
  - lib/nrser/labs/core_ext/binding.rb
323
328
  - lib/nrser/labs/globlin.rb
329
+ - lib/nrser/labs/i8.rb
324
330
  - lib/nrser/labs/index.rb
325
331
  - lib/nrser/labs/stash.rb
326
332
  - lib/nrser/log.rb
@@ -332,6 +338,7 @@ files:
332
338
  - lib/nrser/log/logger.rb
333
339
  - lib/nrser/log/mixin.rb
334
340
  - lib/nrser/log/plugin.rb
341
+ - lib/nrser/log/types.rb
335
342
  - lib/nrser/mean_streak.rb
336
343
  - lib/nrser/mean_streak/document.rb
337
344
  - lib/nrser/message.rb
@@ -443,11 +450,12 @@ files:
443
450
  - spec/lib/nrser/functions/text/words_spec.rb
444
451
  - spec/lib/nrser/functions/tree/each_branch_spec.rb
445
452
  - spec/lib/nrser/functions/tree/leaves_spec.rb
446
- - spec/lib/nrser/functions/tree/map_branch_spec.rb
453
+ - spec/lib/nrser/functions/tree/map_branches_spec.rb
447
454
  - spec/lib/nrser/functions/tree/map_tree_spec.rb
448
455
  - spec/lib/nrser/functions/tree/transform_spec.rb
449
456
  - spec/lib/nrser/functions/tree/transformer_spec.rb
450
457
  - spec/lib/nrser/gem_ext/hamster/json_spec.rb
458
+ - spec/lib/nrser/gem_ext/hamster/to_mutable_spec.rb
451
459
  - spec/lib/nrser/labs/globlin_spec.rb
452
460
  - spec/lib/nrser/labs/index_spec.rb
453
461
  - spec/lib/nrser/mean_streak/design_spec.rb
@@ -535,11 +543,12 @@ test_files:
535
543
  - spec/lib/nrser/functions/text/words_spec.rb
536
544
  - spec/lib/nrser/functions/tree/each_branch_spec.rb
537
545
  - spec/lib/nrser/functions/tree/leaves_spec.rb
538
- - spec/lib/nrser/functions/tree/map_branch_spec.rb
546
+ - spec/lib/nrser/functions/tree/map_branches_spec.rb
539
547
  - spec/lib/nrser/functions/tree/map_tree_spec.rb
540
548
  - spec/lib/nrser/functions/tree/transform_spec.rb
541
549
  - spec/lib/nrser/functions/tree/transformer_spec.rb
542
550
  - spec/lib/nrser/gem_ext/hamster/json_spec.rb
551
+ - spec/lib/nrser/gem_ext/hamster/to_mutable_spec.rb
543
552
  - spec/lib/nrser/labs/globlin_spec.rb
544
553
  - spec/lib/nrser/labs/index_spec.rb
545
554
  - spec/lib/nrser/mean_streak/design_spec.rb