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
@@ -0,0 +1,86 @@
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
3
+
4
+ # Requirements
5
+ # =======================================================================
6
+
7
+ # Project / Package
8
+ # -----------------------------------------------------------------------
9
+ require 'nrser/errors/nicer_error'
10
+
11
+
12
+ # Definitions
13
+ # =======================================================================
14
+
15
+ # This error (or a subclass) is thrown when types fail to
16
+ # {NRSER::Types::Type.check!}.
17
+ #
18
+ class NRSER::Types::CheckError < ::TypeError
19
+
20
+ # Mixins
21
+ # ==========================================================================
22
+
23
+ include NRSER::NicerError
24
+
25
+
26
+ # Attributes
27
+ # ========================================================================
28
+
29
+ # The type that was checked against.
30
+ #
31
+ # @return [NRSER::Types::Type]
32
+ #
33
+ attr_reader :type
34
+
35
+
36
+ # The value that failed the type check.
37
+ #
38
+ # @return [*]
39
+ #
40
+ attr_reader :value
41
+
42
+
43
+ # Constructor
44
+ # ========================================================================
45
+
46
+ # Construct a `NicerError`.
47
+ #
48
+ # @param [*] value:
49
+ # The {#value} that failed the check.
50
+ #
51
+ # @param [NRSER::Types::Type] type:
52
+ # The type that was checked.
53
+ #
54
+ # @param details: (see NRSER::NicerError#initialize)
55
+ #
56
+ # @param **kwds
57
+ # See {NRSER::NicerError#initialize}
58
+ #
59
+ def initialize *message, value:, type:, details: nil, **kwds
60
+ @value = value
61
+ @type = type
62
+
63
+ if details.is_a?( Proc ) && details.arity != 0
64
+ orig_details = details
65
+ details = -> { orig_details.call type: type, value: value }
66
+ end
67
+
68
+ super \
69
+ *message,
70
+ type: type,
71
+ value: value,
72
+ details: details,
73
+ **kwds
74
+ end
75
+
76
+
77
+ # Build default message when none provided.
78
+ #
79
+ # @return [String]
80
+ #
81
+ def default_message
82
+ ["Value", value.inspect, "failed check for type", type.name]
83
+ end # #default_message
84
+
85
+
86
+ end # class NRSER::Types::TypeError
@@ -0,0 +1,82 @@
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
3
+
4
+ # Requirements
5
+ # =======================================================================
6
+
7
+ # Project / Package
8
+ # -----------------------------------------------------------------------
9
+ require 'nrser/errors/nicer_error'
10
+
11
+
12
+ # Definitions
13
+ # =======================================================================
14
+
15
+ # Raised when a {NRSER::Types::Type} fails to load a value from a {String}
16
+ # (via it's `#from_s` method).
17
+ #
18
+ # This is a {NRSER::NicerError}.
19
+ #
20
+ class NRSER::Types::FromStringError < ::ArgumentError
21
+
22
+ # Mixins
23
+ # ==========================================================================
24
+
25
+ # Make life better.
26
+ include NRSER::NicerError
27
+
28
+
29
+ # Attributes
30
+ # ========================================================================
31
+
32
+ # The type that was checked against.
33
+ #
34
+ # @return [NRSER::Types::Type]
35
+ #
36
+ attr_reader :type
37
+
38
+
39
+ # The string we were trying to load from.
40
+ #
41
+ # @return [String]
42
+ #
43
+ attr_reader :string
44
+
45
+
46
+ # Constructor
47
+ # ========================================================================
48
+
49
+ # Construct a `FromStringError`.
50
+ #
51
+ # @param *message (see NRSER::NicerError#initialize)
52
+ #
53
+ # @param [String] string:
54
+ # The string the type was trying to load a value from.
55
+ #
56
+ # @param [NRSER::Types::Type] type:
57
+ # The type that was trying to load.
58
+ #
59
+ # @param **kwds
60
+ # See {NRSER::NicerError#initialize}
61
+ #
62
+ def initialize *message, string:, type:, **kwds
63
+ @string = string
64
+ @type = type
65
+
66
+ super \
67
+ *message,
68
+ type: type,
69
+ string: string,
70
+ **kwds
71
+ end
72
+
73
+
74
+ # Main message to use when none provided to {#initialize}.
75
+ #
76
+ # @return [String]
77
+ #
78
+ def default_message
79
+ ["Failed to load type", type.name, "from string", string.inspect]
80
+ end
81
+
82
+ end # class NRSER::Types::TypeError
@@ -0,0 +1,91 @@
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
3
+
4
+ # Requirements
5
+ # =======================================================================
6
+
7
+ # Stdlib
8
+ # -----------------------------------------------------------------------
9
+
10
+ # Deps
11
+ # -----------------------------------------------------------------------
12
+
13
+ # Project / Package
14
+ # -----------------------------------------------------------------------
15
+
16
+
17
+ # Refinements
18
+ # =======================================================================
19
+
20
+
21
+ # Declarations
22
+ # =======================================================================
23
+
24
+
25
+ # Definitions
26
+ # =======================================================================
27
+
28
+
29
+ # @todo document NRSER::Types::Factory module.
30
+ module NRSER::Types::Factory
31
+
32
+ # Define a type factory.
33
+ #
34
+ # @!macro [attach] factory
35
+ # @param [Hash] **options
36
+ # Common type construction options, see {Type#initialize}.
37
+ #
38
+ # @return [NRSER::Types::Type]
39
+ # The type.
40
+ #
41
+ def def_factory name, maybe: true, aliases: [], &body
42
+ define_singleton_method name, &body
43
+
44
+ aliases.each do |alias_name|
45
+ if self.respond_to? alias_name
46
+ alias_name = alias_name + '_'
47
+ end
48
+
49
+ singleton_class.send :alias_method, alias_name, name
50
+ end
51
+
52
+ if maybe && !name.to_s.end_with?( '?' )
53
+ maybe_name = "#{ name }?".to_sym
54
+
55
+ if self.respond_to? maybe_name
56
+ maybe_name = "#{ name }_?".to_sym
57
+ end
58
+
59
+ # HACK Ugh maybe I wrote this quick to fix it, not sure if it's a decent
60
+ # idea.. basically, need to figure out what `options` keys go
61
+ # to {.maybe} and which ones go to the regular factory... matters
62
+ # for shit like {.attrs} and {.hash_type} 'cause they use option
63
+ # keys (whether they *should* is something I've debated... sigh,
64
+ # it is what it is for now).
65
+ #
66
+ # So they options that go to {.maybe} just go strait through to
67
+ # {Type#initialize}, so just grab that method, see what keys it
68
+ # takes, and then can slice and dice off that...
69
+ #
70
+ maybe_option_keys = Set.new \
71
+ NRSER::Types::Type.
72
+ instance_method( :initialize ).
73
+ parameters.
74
+ select { |param_type, name| param_type == :key }.
75
+ map { |param_type, name| name }
76
+
77
+ define_singleton_method maybe_name do |*args, **options|
78
+ maybe_options = options.slice *maybe_option_keys
79
+ factory_options = options.except *maybe_option_keys
80
+
81
+ maybe public_send( name, *args, **factory_options ), **maybe_options
82
+ end
83
+
84
+ aliases.each do |alias_name|
85
+ singleton_class.send :alias_method, "#{ alias_name }?", maybe_name
86
+ end
87
+
88
+ end
89
+ end
90
+
91
+ end # module NRSER::Types::Factory
@@ -1,41 +1,185 @@
1
- require 'nrser/refinements'
2
- require 'nrser/types/type'
3
-
4
- using NRSER
1
+ require_relative './type'
5
2
 
6
3
  module NRSER::Types
7
-
4
+
5
+ # A type who's members simply are {Hash} instances.
6
+ #
7
+ # Implements {#from_s} to provide JSON/YAML detection, as well as "simple"
8
+ # loading aimed at CLI option values.
9
+ #
8
10
  class HashType < IsA
9
- attr_reader :keys, :values #, :including, :exactly, :min, :max
11
+
12
+ # Constructor
13
+ # ========================================================================
10
14
 
11
- def initialize keys: NRSER::Types::ANY,
12
- values: NRSER::Types::ANY,
13
- **options
15
+ # Instantiate a new `HashType`.
16
+ def initialize **options
14
17
  super ::Hash, **options
18
+ end # #initialize
19
+
20
+
21
+ # Instance Methods
22
+ # ========================================================================
23
+
24
+ # In order to provide the same interface as {HashOfType}, this method
25
+ # always returns {NRSER::Types.any}.
26
+ #
27
+ # @return [NRSER::Types::Type]
28
+ #
29
+ def keys; NRSER::Types.any; end
30
+
31
+
32
+ # In order to provide the same interface as {HashOfType}, this method
33
+ # always returns {NRSER::Types.any}.
34
+ #
35
+ # @return [NRSER::Types::Type]
36
+ #
37
+ def values; NRSER::Types.any; end
38
+
39
+
40
+ protected
41
+ # ========================================================================
42
+
43
+ # Hook to provide custom loading from strings, which will be called by
44
+ # {NRSER::Types::Type#from_s}, unless a `@from_s`
45
+ #
46
+ def custom_from_s string
47
+ # Does it looks like a JSON / inline-YAML object?
48
+ if NRSER.looks_like_json_object? string
49
+ # It does! Load it
50
+ begin
51
+ return YAML.load string
52
+ rescue
53
+ # pass - if we failed to load as JSON, it may just not be JSON, and
54
+ # we can try the split approach below.
55
+ end
56
+ end
57
+
58
+ # Try parsing as a "simple string", aimed at CLI option values.
59
+ from_simple_s string
60
+ end
61
+
62
+
63
+ def from_simple_s string
64
+ hash = {}
65
+
66
+ pair_strs = string.split NRSER::Types::ArrayType::DEFAULT_SPLIT_WITH
67
+
68
+ pair_strs.each do |pair_str|
69
+ key_str, match, value_str = pair_str.rpartition /\:\s*/m
70
+
71
+ if match.empty?
72
+ raise NRSER::Types::FromStringError.new(
73
+ "Could not split pair string", pair_str,
74
+ type: self,
75
+ string: string,
76
+ pair_str: pair_str,
77
+ ) do
78
+ <<~END
79
+ Trying to parse a {Hash} out of a string using the "simple"
80
+ approach, which splits
81
+
82
+ 1. First by `,` (followed by any amount of whitespace)
83
+ 2. Then by the last `:` in each of those splits (also followed)
84
+ by any amount of whitespace)
85
+ END
86
+ end
87
+ end
88
+
89
+ key = if keys == NRSER::Types.any
90
+ key_str
91
+ else
92
+ keys.from_s key_str
93
+ end
94
+
95
+ value = if values == NRSER::Types.any
96
+ value_str
97
+ else
98
+ values.from_s value_str
99
+ end
100
+
101
+ hash[key] = value
102
+ end
103
+
104
+ hash
105
+ end # #from_simple_s
106
+
107
+ public # end protected *****************************************************
108
+
109
+ end # class HashType
110
+
111
+
112
+ # A {Hash} type with typed keys and/or values.
113
+ #
114
+ class HashOfType < HashType
115
+
116
+ # Attributes
117
+ # ========================================================================
118
+
119
+ # The type of the hash keys.
120
+ #
121
+ # @return [NRSER::Types::Type]
122
+ #
123
+ attr_reader :keys
124
+
125
+
126
+ # The type of the hash values.
127
+ #
128
+ # @return [NRSER::Types::Type]
129
+ #
130
+ attr_reader :values
131
+
132
+
133
+ # Constructor
134
+ # ========================================================================
135
+
136
+ def initialize keys: NRSER::Types.any,
137
+ values: NRSER::Types.any,
138
+ **options
139
+ super **options
15
140
 
16
141
  @keys = NRSER::Types.make keys
17
142
  @values = NRSER::Types.make values
18
143
  end
19
144
 
20
- def test value
21
- return false unless super(value)
22
-
23
- if keys == NRSER::Types::ANY && values == NRSER::Types::ANY
24
- return true
25
- end
145
+
146
+ # Instance Methods
147
+ # ========================================================================
148
+
149
+ # Overridden to check that both the {#keys} and {#values} types can
150
+ # load from a string.
151
+ #
152
+ # @see NRSER::Types::Type#has_from_s?
153
+ #
154
+ def has_from_s?
155
+ !@from_s.nil? || [keys, values].all?( &:has_from_s )
156
+ end
157
+
158
+
159
+ # @see NRSER::Types::Type#test
160
+ #
161
+ # @return [Boolean]
162
+ #
163
+ def test? value
164
+ return false unless super( value )
26
165
 
27
166
  value.all? { |k, v|
28
- keys.test(k) && values.test(v)
167
+ keys.test( k ) && values.test( v )
29
168
  }
30
169
  end
31
170
 
32
- def default_name
33
- "Hash{#{ @keys.name }=>#{ @values.name }}"
171
+
172
+ # @see NRSER::Types::Type#explain
173
+ #
174
+ # @return [String]
175
+ #
176
+ def explain
177
+ "Hash<#{ keys.explain }, #{ values.explain }>"
34
178
  end
179
+
35
180
  end # HashType
181
+
36
182
 
37
-
38
-
39
183
  # Type satisfied by {Hash} instances.
40
184
  #
41
185
  # @param [Array] *args
@@ -47,14 +191,15 @@ module NRSER::Types
47
191
  # @return [NRSER::Types::Type]
48
192
  # Newly constructed hash type from `args`.
49
193
  #
50
- def_factory :hash_type, aliases: [:dict, :hash_] do |*args|
51
- if args.empty?
52
- HASH
194
+ def_factory(
195
+ :hash_type,
196
+ aliases: [ :dict, :hash_ ]
197
+ ) do |**kwds|
198
+ if kwds.key?( :keys ) || kwds.key?( :values )
199
+ HashOfType.new **kwds
53
200
  else
54
- HashType.new *args
201
+ HashType.new **kwds
55
202
  end
56
203
  end
57
204
 
58
- HASH = HashType.new.freeze
59
-
60
205
  end
@@ -1,26 +1,39 @@
1
- # Refinements
2
- # =======================================================================
3
-
4
- using NRSER
5
-
6
-
7
- # Definitions
8
- # =======================================================================
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
9
3
 
10
4
  module NRSER::Types
11
5
 
12
6
  # Type that tests value for membership in a group object via that object's
13
7
  # `#include?` method.
14
8
  #
9
+ # @todo
10
+ # I think I want to get rid of {.where}... which would elevate this to
11
+ # it's own class as a "fundamental" concept (I guess)... not so sure,
12
+ # really. The idea of membership is pretty wide-spread and important,
13
+ # but it's a bit a vague and inconsistently implemented things.
14
+ #
15
15
  # @param [#include?] group
16
16
  # `#include?` will be called on this value to determine type membership.
17
17
  #
18
18
  # @return [NRSER::Types::Type]
19
19
  #
20
- def self.in group, **options
21
- where( name: "In(#{ group })", **options ) { |value|
22
- group.include? value
23
- }
20
+ def_factory(
21
+ :in,
22
+ aliases: [ :member_of ],
23
+ ) do |group, **options|
24
+ unless group.respond_to? :include?
25
+ raise NRSER::ArgumentError,
26
+ "In `group` must respond to `:include?`",
27
+ group: group
28
+ end
29
+
30
+ # Provide a some-what useful default name
31
+ options[:name] ||= "In<#{ NRSER.smart_ellipsis group.inspect, 64 }>"
32
+
33
+ # Unless a `from_s` is provided, just use the identity
34
+ options[:from_s] ||= ->( s ) { s }
35
+
36
+ where( **options ) { |value| group.include? value }
24
37
  end # .in
25
38
 
26
39
  end # module NRSER::Types
@@ -1,22 +1,58 @@
1
- require 'nrser/refinements'
2
- require 'nrser/types/type'
3
- using NRSER
1
+
2
+ # Requirements
3
+ # ========================================================================
4
+
5
+ # Stdlib
6
+ # ------------------------------------------------------------------------
7
+
8
+ # Deps
9
+ # ------------------------------------------------------------------------
10
+
11
+ # Need {Module#anonymous?}
12
+ require 'active_support/core_ext/module/anonymous'
13
+
14
+
15
+ # Project / Package
16
+ # ------------------------------------------------------------------------
17
+
18
+ require_relative './type'
19
+
4
20
 
5
21
  module NRSER::Types
22
+
23
+ # Type satisfied only by it's exact {#value} object (identity comparison
24
+ # via `#equal?`).
25
+ #
6
26
  class Is < NRSER::Types::Type
27
+
28
+ # Attributes
29
+ # ========================================================================
30
+
7
31
  attr_reader :value
8
32
 
9
33
  def initialize value, **options
10
34
  super **options
11
-
12
35
  @value = value
13
36
  end
14
37
 
15
- def default_name
16
- "Is(#{ @value.inspect })"
38
+ def explain
39
+ case value
40
+ when Module
41
+ module_type = if value.is_a?( Class ) then 'Class' else 'Module' end
42
+
43
+ name = if value.anonymous?
44
+ value.to_s.split( ':' ).last[0...-1]
45
+ else
46
+ value.name
47
+ end
48
+
49
+ "#{ module_type }<#{ name }>"
50
+ else
51
+ value.inspect
52
+ end
17
53
  end
18
54
 
19
- def test value
55
+ def test? value
20
56
  @value.equal? value
21
57
  end
22
58
 
@@ -26,19 +62,15 @@ module NRSER::Types
26
62
  @value == other.value )
27
63
  end
28
64
 
29
- # @return [String]
30
- # a brief string description of the type - just it's {#name} surrounded
31
- # by some back-ticks to make it easy to see where it starts and stops.
32
- #
33
- def to_s
34
- "{ x ≡ #{ @value.inspect } }"
35
- end
36
-
37
- alias_method :inspect, :to_s
38
65
  end # Is
39
66
 
40
- # an exact value (using ===)
41
- def self.is value, **options
67
+
68
+ # Satisfied by the exact value only (identity comparison via
69
+ # `#equal?`).
70
+ #
71
+ # Useful for things like {Module}, {Class}, {Fixnum}, {Symbol}, `true`, etc.
72
+ #
73
+ def_factory :is do |value, **options|
42
74
  Is.new value, **options
43
75
  end
44
76