nrser 0.2.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (188) hide show
  1. checksums.yaml +4 -4
  2. data/lib/nrser/char/alpha_numeric_sub.rb +1 -2
  3. data/lib/nrser/char.rb +0 -6
  4. data/lib/nrser/core_ext/array.rb +120 -0
  5. data/lib/nrser/core_ext/binding.rb +44 -0
  6. data/lib/nrser/{functions → core_ext}/enumerable/find_map.rb +18 -15
  7. data/lib/nrser/{ext → core_ext}/enumerable.rb +10 -24
  8. data/lib/nrser/core_ext/exception.rb +30 -0
  9. data/lib/nrser/core_ext/hash/extract_values_at.rb +49 -0
  10. data/lib/nrser/core_ext/hash/transform_values_with_keys.rb +24 -0
  11. data/lib/nrser/core_ext/hash.rb +50 -0
  12. data/lib/nrser/core_ext/module/method_objects.rb +96 -0
  13. data/lib/nrser/core_ext/module/names.rb +69 -0
  14. data/lib/nrser/core_ext/module/source_locations.rb +214 -0
  15. data/lib/nrser/core_ext/module.rb +2 -0
  16. data/lib/nrser/core_ext/object/lazy_var.rb +31 -0
  17. data/lib/nrser/core_ext/object.rb +46 -0
  18. data/lib/nrser/core_ext/open_struct.rb +6 -0
  19. data/lib/nrser/{ext → core_ext}/pathname.rb +8 -5
  20. data/lib/nrser/{ext → core_ext}/string.rb +6 -12
  21. data/lib/nrser/core_ext/symbol.rb +13 -0
  22. data/lib/nrser/core_ext/time.rb +46 -0
  23. data/lib/nrser/core_ext.rb +13 -0
  24. data/lib/nrser/errors/abstract_method_error.rb +150 -0
  25. data/lib/nrser/errors/argument_error.rb +42 -0
  26. data/lib/nrser/errors/nicer_error.rb +298 -72
  27. data/lib/nrser/errors/type_error.rb +46 -0
  28. data/lib/nrser/errors.rb +4 -53
  29. data/lib/nrser/ext/tree.rb +3 -0
  30. data/lib/nrser/functions/enumerable/associate.rb +6 -9
  31. data/lib/nrser/functions/enumerable/include_slice.rb +2 -3
  32. data/lib/nrser/functions/enumerable.rb +1 -3
  33. data/lib/nrser/functions/exception.rb +1 -1
  34. data/lib/nrser/functions/hash.rb +0 -6
  35. data/lib/nrser/functions/merge_by.rb +2 -2
  36. data/lib/nrser/functions/module/method_objects.rb +77 -0
  37. data/lib/nrser/functions/module.rb +1 -2
  38. data/lib/nrser/functions/open_struct.rb +25 -35
  39. data/lib/nrser/functions/proc.rb +1 -6
  40. data/lib/nrser/functions/string/looks_like.rb +32 -1
  41. data/lib/nrser/functions/string.rb +1 -40
  42. data/lib/nrser/functions/text/lines.rb +2 -1
  43. data/lib/nrser/functions.rb +0 -1
  44. data/lib/nrser/graph/tsorter.rb +41 -0
  45. data/lib/nrser/labs/core_ext/binding.rb +37 -0
  46. data/lib/nrser/labs/stash.rb +372 -0
  47. data/lib/nrser/{logging → log}/appender/sync.rb +3 -3
  48. data/lib/nrser/log/appender.rb +3 -0
  49. data/lib/nrser/{logging → log}/formatters/color.rb +47 -20
  50. data/lib/nrser/log/formatters/mixin.rb +270 -0
  51. data/lib/nrser/{logging → log}/formatters.rb +0 -0
  52. data/lib/nrser/log/logger.rb +229 -0
  53. data/lib/nrser/log/mixin.rb +56 -0
  54. data/lib/nrser/log.rb +723 -0
  55. data/lib/nrser/message.rb +24 -3
  56. data/lib/nrser/meta/source/location.rb +158 -0
  57. data/lib/nrser/meta.rb +1 -1
  58. data/lib/nrser/props/class_methods.rb +118 -0
  59. data/lib/nrser/props/immutable/hash.rb +111 -0
  60. data/lib/nrser/props/immutable/hash_variable.rb +82 -0
  61. data/lib/nrser/props/immutable/instance_variables.rb +48 -0
  62. data/lib/nrser/props/immutable/vector.rb +107 -0
  63. data/lib/nrser/props/instance_methods.rb +184 -0
  64. data/lib/nrser/props/metadata.rb +359 -0
  65. data/lib/nrser/props/mutable/instance_variables.rb +60 -0
  66. data/lib/nrser/props/mutable/stash.rb +199 -0
  67. data/lib/nrser/{meta/props → props}/prop.rb +217 -112
  68. data/lib/nrser/props/storage/instance_variable.rb +85 -0
  69. data/lib/nrser/props/storage/instance_variables.rb +67 -0
  70. data/lib/nrser/props/storage/key.rb +88 -0
  71. data/lib/nrser/props.rb +9 -0
  72. data/lib/nrser/refinements/sugar.rb +41 -0
  73. data/lib/nrser/refinements/types.rb +2 -2
  74. data/lib/nrser/refinements.rb +14 -16
  75. data/lib/nrser/rspex/example_group/describe_attribute.rb +24 -0
  76. data/lib/nrser/rspex/example_group/describe_called_with.rb +1 -6
  77. data/lib/nrser/rspex/example_group/{describe_use_case.rb → describe_case.rb} +6 -3
  78. data/lib/nrser/rspex/example_group/describe_class.rb +1 -0
  79. data/lib/nrser/rspex/example_group/describe_group.rb +29 -0
  80. data/lib/nrser/rspex/example_group/describe_instance_method.rb +2 -2
  81. data/lib/nrser/rspex/example_group/describe_message.rb +35 -0
  82. data/lib/nrser/rspex/example_group/describe_method.rb +23 -2
  83. data/lib/nrser/rspex/example_group/describe_module.rb +19 -0
  84. data/lib/nrser/rspex/example_group/describe_response_to.rb +32 -0
  85. data/lib/nrser/rspex/example_group/describe_section.rb +38 -0
  86. data/lib/nrser/rspex/example_group/describe_sent_to.rb +52 -0
  87. data/lib/nrser/rspex/example_group/describe_source_file.rb +49 -0
  88. data/lib/nrser/rspex/example_group/describe_spec_file.rb +41 -108
  89. data/lib/nrser/rspex/example_group/describe_when.rb +14 -7
  90. data/lib/nrser/rspex/example_group/describe_x.rb +39 -12
  91. data/lib/nrser/rspex/example_group/overrides.rb +66 -0
  92. data/lib/nrser/rspex/example_group.rb +20 -252
  93. data/lib/nrser/rspex/format.rb +83 -17
  94. data/lib/nrser/rspex.rb +4 -34
  95. data/lib/nrser/sugar/method_missing_forwarder.rb +50 -0
  96. data/lib/nrser/{env → sys/env}/path.rb +1 -2
  97. data/lib/nrser/{env.rb → sys/env.rb} +2 -1
  98. data/lib/nrser/sys.rb +5 -0
  99. data/lib/nrser/types/any.rb +36 -7
  100. data/lib/nrser/types/{array.rb → arrays.rb} +32 -81
  101. data/lib/nrser/types/attrs.rb +68 -15
  102. data/lib/nrser/types/booleans.rb +95 -34
  103. data/lib/nrser/types/bounded.rb +12 -10
  104. data/lib/nrser/types/combinators.rb +74 -37
  105. data/lib/nrser/types/errors/check_error.rb +86 -0
  106. data/lib/nrser/types/errors/from_string_error.rb +82 -0
  107. data/lib/nrser/types/factory.rb +91 -0
  108. data/lib/nrser/types/hashes.rb +171 -26
  109. data/lib/nrser/types/in.rb +25 -12
  110. data/lib/nrser/types/is.rb +50 -18
  111. data/lib/nrser/types/is_a.rb +52 -33
  112. data/lib/nrser/types/labels.rb +6 -33
  113. data/lib/nrser/types/maybe.rb +12 -4
  114. data/lib/nrser/types/nil.rb +24 -4
  115. data/lib/nrser/types/not.rb +6 -16
  116. data/lib/nrser/types/numbers.rb +94 -57
  117. data/lib/nrser/types/pairs.rb +57 -57
  118. data/lib/nrser/types/paths.rb +112 -133
  119. data/lib/nrser/types/responds.rb +64 -74
  120. data/lib/nrser/types/shape.rb +29 -24
  121. data/lib/nrser/types/strings.rb +25 -17
  122. data/lib/nrser/types/symbols.rb +19 -17
  123. data/lib/nrser/types/trees.rb +18 -70
  124. data/lib/nrser/types/tuples.rb +36 -40
  125. data/lib/nrser/types/type.rb +342 -91
  126. data/lib/nrser/types/when.rb +40 -18
  127. data/lib/nrser/types/where.rb +94 -9
  128. data/lib/nrser/types.rb +72 -63
  129. data/lib/nrser/version.rb +1 -1
  130. data/lib/nrser.rb +18 -18
  131. data/spec/lib/nrser/{functions/binding/template_spec.rb → core_ext/binding/erb_spec.rb} +5 -5
  132. data/spec/lib/nrser/{functions → core_ext}/enumerable/find_map_spec.rb +8 -6
  133. data/spec/lib/nrser/{refinements → core_ext}/hash_spec.rb +9 -22
  134. data/spec/lib/nrser/errors/abstract_method_error_spec.rb +12 -5
  135. data/spec/lib/nrser/functions/enumerable/{to_h_by_spec.rb → associate_spec.rb} +1 -1
  136. data/spec/lib/nrser/functions/merge_by_spec.rb +1 -1
  137. data/spec/lib/nrser/functions/tree/each_branch_spec.rb +3 -3
  138. data/spec/lib/nrser/functions/tree/transform_spec.rb +14 -15
  139. data/spec/lib/nrser/gem_ext/hamster/json_spec.rb +4 -0
  140. data/spec/lib/nrser/meta/source/location_spec.rb +86 -0
  141. data/spec/lib/nrser/props/immutable/hash_spec.rb +297 -0
  142. data/spec/lib/nrser/props/immutable/vector_spec.rb +296 -0
  143. data/spec/lib/nrser/{meta/props_spec.rb → props/original_props_spec.rb} +11 -16
  144. data/spec/lib/nrser/{meta/props → props}/to_and_from_data_spec.rb +10 -8
  145. data/spec/lib/nrser/refinements/array_spec.rb +2 -15
  146. data/spec/lib/nrser/refinements/erb_spec.rb +5 -7
  147. data/spec/lib/nrser/refinements/set_spec.rb +2 -15
  148. data/spec/lib/nrser/{env → sys/env}/path/insert_spec.rb +4 -2
  149. data/spec/lib/nrser/{env → sys/env}/path_spec.rb +4 -2
  150. data/spec/lib/nrser/types/array_spec.rb +8 -8
  151. data/spec/lib/nrser/types/paths_spec.rb +15 -18
  152. data/spec/spec_helper.rb +4 -0
  153. metadata +109 -69
  154. data/lib/nrser/ext/binding.rb +0 -36
  155. data/lib/nrser/ext/module.rb +0 -62
  156. data/lib/nrser/ext.rb +0 -8
  157. data/lib/nrser/functions/binding.rb +0 -76
  158. data/lib/nrser/functions/enumerable/map_keys.rb +0 -0
  159. data/lib/nrser/functions/enumerable/map_values.rb +0 -94
  160. data/lib/nrser/functions/hash/deep_merge.rb +0 -57
  161. data/lib/nrser/functions/hash/except_keys.rb +0 -44
  162. data/lib/nrser/functions/hash/slice_keys.rb +0 -43
  163. data/lib/nrser/functions/hash/stringify_keys.rb +0 -55
  164. data/lib/nrser/functions/hash/symbolize_keys.rb +0 -57
  165. data/lib/nrser/functions/hash/transform_keys.rb +0 -140
  166. data/lib/nrser/functions/module/methods.rb +0 -206
  167. data/lib/nrser/functions/module/source_locations.rb +0 -213
  168. data/lib/nrser/logging/appender.rb +0 -3
  169. data/lib/nrser/logging.rb +0 -353
  170. data/lib/nrser/meta/props/base.rb +0 -31
  171. data/lib/nrser/meta/props.rb +0 -357
  172. data/lib/nrser/refinements/array.rb +0 -133
  173. data/lib/nrser/refinements/binding.rb +0 -6
  174. data/lib/nrser/refinements/enumerator.rb +0 -5
  175. data/lib/nrser/refinements/exception.rb +0 -35
  176. data/lib/nrser/refinements/hash.rb +0 -150
  177. data/lib/nrser/refinements/module.rb +0 -5
  178. data/lib/nrser/refinements/object.rb +0 -42
  179. data/lib/nrser/refinements/open_struct.rb +0 -28
  180. data/lib/nrser/refinements/pathname.rb +0 -5
  181. data/lib/nrser/refinements/set.rb +0 -5
  182. data/lib/nrser/refinements/string.rb +0 -5
  183. data/lib/nrser/refinements/symbol.rb +0 -20
  184. data/lib/nrser/rspex/described.rb +0 -99
  185. data/spec/design/mapping_spec.rb +0 -42
  186. data/spec/lib/nrser/functions/hash_spec.rb +0 -41
  187. data/spec/lib/nrser/functions/string/truncate_spec.rb +0 -11
  188. data/spec/lib/nrser/refinements/truncate_spec.rb +0 -10
data/lib/nrser/message.rb CHANGED
@@ -52,7 +52,7 @@ module NRSER
52
52
 
53
53
  # Name of method the message is for.
54
54
  #
55
- # @return [Symbol | String]
55
+ # @return [Symbol]
56
56
  #
57
57
  attr_reader :symbol
58
58
 
@@ -83,12 +83,33 @@ module NRSER
83
83
  # Optional block that should be sent.
84
84
  #
85
85
  def initialize symbol, *args, &block
86
- @symbol = symbol
86
+ @symbol = symbol.to_sym
87
87
  @args = args
88
88
  @block = block
89
89
  end
90
90
 
91
91
 
92
+ def options
93
+ if args.last.is_a? Hash
94
+ args.last
95
+ else
96
+ {}
97
+ end
98
+ end
99
+
100
+
101
+ def symbolize_options
102
+ if args.last.is_a? Hash
103
+ self.class.new \
104
+ symbol,
105
+ *args[0..-2],
106
+ args.last.sym_keys
107
+ else
108
+ self
109
+ end
110
+ end
111
+
112
+
92
113
  # Creates a {Proc} that accepts a single `receiver` argument and calls
93
114
  # {#sent_to} on it, allowing messages to be used via the `&` operator
94
115
  # in `map`, etc.
@@ -114,7 +135,7 @@ module NRSER
114
135
  end
115
136
 
116
137
  alias_method :to_sender, :to_proc
117
-
138
+
118
139
 
119
140
  # Send this instance to a receiver object.
120
141
  #
@@ -0,0 +1,158 @@
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
+ require 'nrser/props'
17
+ require 'nrser/props/immutable/vector'
18
+
19
+
20
+ # Refinements
21
+ # =======================================================================
22
+
23
+ using NRSER::Types
24
+
25
+
26
+ # Declarations
27
+ # =======================================================================
28
+
29
+ module NRSER::Meta::Source; end
30
+
31
+
32
+ # Definitions
33
+ # =======================================================================
34
+
35
+ # @todo document NRSER::Meta::Source::Location class.
36
+ #
37
+ class NRSER::Meta::Source::Location < Hamster::Vector
38
+
39
+ # Mixins
40
+ # ============================================================================
41
+
42
+ include NRSER::Props::Immutable::Vector
43
+
44
+
45
+ # Class Methods
46
+ # ============================================================================
47
+
48
+ # Given an {Enumerable} of {Method} objects, return a {Hash} mapping their
49
+ # {Method#name} to the method's {NRSER::Meta::Source::Location}.
50
+ #
51
+ # @note
52
+ # We map the names instead of the {Method} objects themselves because
53
+ # aliases produce two different {Method} objects that `#==` and `#hash`
54
+ # the same, preventing them both from being {Hash} keys.
55
+ #
56
+ # @param [Enumerable<Method>] methods
57
+ # Methods you want the source locations for.
58
+ #
59
+ # @param [Boolean] only_valid:
60
+ # When `true` filter the results to only those that are {#valid?}.
61
+ #
62
+ # @return [Hash<Symbol, NRSER::Meta::Source::Location>]
63
+ # Map of method name to their source locations.
64
+ #
65
+ def self.for_methods methods, only_valid: false
66
+ all = methods.map { |method|
67
+ [ method.name, NRSER::Meta::Source::Location.new( method ) ]
68
+ }.to_h
69
+
70
+ if only_valid
71
+ all.select { |method, location| location.valid? }
72
+ else
73
+ all
74
+ end
75
+ end # .for_methods
76
+
77
+
78
+ # Props
79
+ # ======================================================================
80
+
81
+ prop :file, type: t.abs_path?, default: nil, index: 0
82
+ prop :line, type: t.pos_int?, default: nil, index: 1
83
+
84
+
85
+ # Constructor
86
+ # ============================================================================
87
+
88
+ # Override to allow argument to be `nil` for when {Method#source_location}
89
+ # weirdly returns `nil`.
90
+ #
91
+ # @param [(#[] & (#each_pair | #each_index)) | nil ] source
92
+ # Source to construct from:
93
+ #
94
+ # 1. `#[] & (#each_pair | #each_index)`
95
+ # 1. Hash-like that responds to `#each_pair` and contains prop
96
+ # value sources keyed by their names.
97
+ #
98
+ # Supports standard propertied class construction.
99
+ #
100
+ # **Examples:**
101
+ #
102
+ # {file: '/some/abs/path.rb', line: 88}
103
+ # {file: '/some/abs/path.rb', line: nil}
104
+ # {file: nil, line: 88}
105
+ # {file: nil, line: nil}
106
+ # {}
107
+ #
108
+ # 2. Array-like that responds to `#each_index` and contains prop
109
+ # values sources indexed by their non-negative integer indexes.
110
+ #
111
+ # Supports the output of {Method#source_location}.
112
+ #
113
+ # **Examples:**
114
+ #
115
+ # ['/some/abs/path.rb', 88]
116
+ # ['/some/abs/path.rb', nil]
117
+ # [nil, 88]
118
+ # [nil, nil]
119
+ # []
120
+ #
121
+ # 2. `nil` - Swapped for `{]` to support times I'm pretty sure I've seen
122
+ # {Method#source_location} return strait-up `nil`.
123
+ #
124
+ #
125
+ def initialize source
126
+ source = source.source_location if source.respond_to? :source_location
127
+ source = {} if source.nil?
128
+ super source
129
+ end
130
+
131
+
132
+ # Instance Methods
133
+ # ======================================================================
134
+
135
+ # Do we have a file and a line?
136
+ #
137
+ # Sometimes `#source_location` gives back `nil` values or just `nil`
138
+ # (in which case we set both {#file} and {#line} to `nil`). I think this
139
+ # has to do with C extensions and other weirdness.
140
+ #
141
+ # Anyways, this helps you handle it.
142
+ #
143
+ # @return [Boolean]
144
+ #
145
+ def valid?
146
+ !( file.nil? && line.nil? )
147
+ end # #valid?
148
+
149
+
150
+ # @return [String]
151
+ # a short string describing the instance.
152
+ #
153
+ def to_s
154
+ "#{ file || '???' }:#{ line || '???' }"
155
+ end # #to_s
156
+
157
+
158
+ end # class NRSER::Meta::Source::Location
data/lib/nrser/meta.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  module NRSER::Meta; end
2
2
 
3
3
  require_relative './meta/class_attrs'
4
- require_relative './meta/props'
4
+ require_relative './meta/source/location'
@@ -0,0 +1,118 @@
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
+ require_relative './metadata'
16
+
17
+ # Refinements
18
+ # =======================================================================
19
+
20
+
21
+ # Declarations
22
+ # =======================================================================
23
+
24
+ module NRSER::Props; end
25
+
26
+
27
+ # Definitions
28
+ # =======================================================================
29
+
30
+
31
+ # Class method "macros" that are extended in to data classes, providing the
32
+ # declaration interface.
33
+ #
34
+ module NRSER::Props::ClassMethods
35
+
36
+ include NRSER::Log::Mixin
37
+
38
+ # Get the metadata object for this class, creating it if it doesn't exist.
39
+ #
40
+ # @return [NRSER::Props::Metadata]
41
+ #
42
+ def metadata
43
+ # TODO Move into {NRSER::Props::Metadata}?
44
+ #
45
+ unless NRSER::Props::Metadata.has_metadata? self
46
+ instance_variable_set \
47
+ NRSER::Props::Metadata::VARIABLE_NAME,
48
+ NRSER::Props::Metadata.new( self )
49
+ end
50
+
51
+ NRSER::Props::Metadata.metadata_for self
52
+ end
53
+
54
+
55
+ def props *args, &block
56
+ metadata.props *args, &block
57
+ end
58
+
59
+
60
+ def prop *args, &block
61
+ metadata.prop *args, &block
62
+ end
63
+
64
+
65
+ def invariants *args, &block
66
+ metadata.invariants *args, &block
67
+ end
68
+
69
+
70
+ def invariant *args, &block
71
+ metadata.invariant *args, &block
72
+ end
73
+
74
+
75
+ # Instantiate from a data hash.
76
+ #
77
+ # @todo
78
+ # This needs to be extended to handle prop'd classes nested in
79
+ # arrays and hashes... but for the moment, it is what it is.
80
+ #
81
+ # This *may* have been fixed...?
82
+ #
83
+ # @param [#each_pair] data
84
+ #
85
+ # @return [self]
86
+ #
87
+ # @raise [NRSER::ArgumentError]
88
+ # If `data` does not respond to `#each_pair`.
89
+ #
90
+ def from_data data
91
+ values = {}
92
+ props = self.props
93
+
94
+ unless data.respond_to? :each_pair
95
+ raise NRSER::ArgumentError.new \
96
+ "`data` argument must respond to `#each_pair`",
97
+ data: data,
98
+ class: self
99
+ end
100
+
101
+ data.each_pair do |data_key, data_value|
102
+ prop_key = case data_key
103
+ when Symbol
104
+ data_key
105
+ when String
106
+ data_key.to_sym
107
+ end
108
+
109
+ if prop_key &&
110
+ (prop = props[prop_key])
111
+ values[prop_key] = prop.value_from_data data_value
112
+ end
113
+ end
114
+
115
+ self.new values
116
+ end # #from_data
117
+
118
+ end # module NRSER::Props::ClassMethods
@@ -0,0 +1,111 @@
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
3
+
4
+ # Requirements
5
+ # =======================================================================
6
+
7
+ # Deps
8
+ # -----------------------------------------------------------------------
9
+ require 'hamster'
10
+
11
+ # Project / Package
12
+ # -----------------------------------------------------------------------
13
+ require_relative '../storage/key'
14
+
15
+
16
+ # Declarations
17
+ # =======================================================================
18
+
19
+ module NRSER::Props::Immutable; end
20
+
21
+
22
+ # Definitions
23
+ # =======================================================================
24
+
25
+ # Mixin for classes that extend {Hamster::Hash} and will use itself as the
26
+ # property value storage.
27
+ #
28
+ module NRSER::Props::Immutable::Hash
29
+
30
+ # Constants
31
+ # ==========================================================================
32
+
33
+ STORAGE = NRSER::Props::Storage::Key.new immutable: true, key_type: :name
34
+
35
+
36
+ # Module Methods
37
+ # ======================================================================
38
+
39
+ def self.included base
40
+ unless base < Hamster::Hash
41
+ raise binding.erb <<~END
42
+ This class is only for including in {Hamster::Hash} subclasses!
43
+ END
44
+ end
45
+
46
+ base.include NRSER::Props
47
+ base.metadata.storage STORAGE
48
+ base.metadata.freeze
49
+
50
+ base.extend ClassMethods
51
+ base.include InstanceMethods
52
+ end
53
+
54
+
55
+ # Mixin Methods
56
+ # ======================================================================
57
+
58
+ # Methods mixed in at the class-level.
59
+ #
60
+ module ClassMethods
61
+ # {Hamster::Hash} uses `.alloc` to quickly create derived instances
62
+ # when it knows the instance variables. We need to hook into that to
63
+ # check the prop types.
64
+ #
65
+ # @param (see Hamster::Hash.alloc)
66
+ #
67
+ # @return [Hamster::Hash]
68
+ # The new instance, which will be of the propertied subclass of
69
+ # {Hamster::Hash}.
70
+ #
71
+ # @raise [TypeError]
72
+ # If the prop values of the new vector don't satisfy the prop types.
73
+ #
74
+ def alloc *args
75
+ super( *args ).tap do |new_instance|
76
+ self.props( only_primary: true ).values.each do |prop|
77
+ prop.check! new_instance[prop.name]
78
+ end
79
+ end
80
+ end
81
+ end # module ClassMethods
82
+
83
+ module InstanceMethods
84
+ # Constructor
85
+ # ----------------------------------------------------------------------------
86
+
87
+ # Since including classes are using themselves as storage, we need to tap
88
+ # into the `#initialize` chain in order to load property values from sources
89
+ # and pass an {Array} up to the super-method to instantiate the
90
+ # {Hamster::Hash}.
91
+ #
92
+ def initialize values = {}
93
+ # Handles things like `[[:x, 1], [:y, 2]]`
94
+ values = values.to_h unless values.respond_to?( :each_pair )
95
+
96
+ super_values = {}
97
+
98
+ self.class.metadata.each_primary_prop_value_from( values ) { |prop, value|
99
+ super_values[prop.name] = value
100
+ }
101
+
102
+ super super_values
103
+
104
+ # Check additional type invariants
105
+ self.class.invariants.each do |type|
106
+ type.check self
107
+ end
108
+ end # #initialize
109
+ end
110
+
111
+ end # module NRSER::Props::Immutable::Hash
@@ -0,0 +1,82 @@
1
+ # Requirements
2
+ # =======================================================================
3
+
4
+ # Stdlib
5
+ # -----------------------------------------------------------------------
6
+
7
+ # Deps
8
+ # -----------------------------------------------------------------------
9
+
10
+ # Project / Package
11
+ # -----------------------------------------------------------------------
12
+ require_relative '../storage/key'
13
+ require_relative '../storage/instance_variable'
14
+
15
+
16
+ # Declarations
17
+ # =======================================================================
18
+
19
+ module NRSER; end
20
+ module NRSER::Props; end
21
+
22
+
23
+ # Definitions
24
+ # =======================================================================
25
+
26
+ # Mix-in to store property values in an immutable {Hamster::Hash} instance
27
+ # in an instance variable.
28
+ #
29
+ # This is basically an improvement of how the original props implementation
30
+ # worked.
31
+ #
32
+ module NRSER::Props::Immutable::HashVariable
33
+
34
+ KEY_STORAGE = NRSER::Props::Storage::Key.new immutable: true, key_type: :name
35
+
36
+ INSTANCE_VARIABLE_STORAGE = \
37
+ NRSER::Props::Storage::InstanceVariable.new sub_storage: KEY_STORAGE
38
+
39
+
40
+ # Class Methods
41
+ # ======================================================================
42
+
43
+ def self.included base
44
+ base.include NRSER::Props
45
+ base.metadata.storage INSTANCE_VARIABLE_STORAGE
46
+ base.metadata.freeze
47
+ end
48
+
49
+
50
+ # Constructor
51
+ # ======================================================================
52
+
53
+ # Instantiate a new `NRSER::Props::Immutable::Vector`.
54
+ def initialize_props values = {}
55
+ prop_values = {}
56
+
57
+ self.class.metadata.each_primary_prop_value_from( values ) { |prop, value|
58
+ prop_values[prop.name] = value
59
+ }
60
+
61
+ instance_variable_set self.class.metadata.storage.var_name,
62
+ Hamster::Hash.new( values )
63
+
64
+ # Check additional type invariants
65
+ self.class.invariants.each do |type|
66
+ type.check self
67
+ end
68
+ end # #initialize
69
+
70
+ end # module NRSER::Props::Immutable::HashVariable
71
+
72
+
73
+ # @todo document NRSER::Props::Immutable::HashVariable::Base module.
74
+ class NRSER::Props::Immutable::HashVariable::Base
75
+
76
+ include NRSER::Props::Immutable::HashVariable
77
+
78
+ def initialize values = {}
79
+ initialize_props values
80
+ end
81
+
82
+ end # class NRSER::Props::Immutable::HashVariable::Base
@@ -0,0 +1,48 @@
1
+ # Requirements
2
+ # =======================================================================
3
+
4
+ # Project / Package
5
+ # -----------------------------------------------------------------------
6
+ require_relative '../../props'
7
+ require_relative '../storage/key'
8
+ require_relative '../storage/instance_variables'
9
+
10
+
11
+ # Definitions
12
+ # =======================================================================
13
+
14
+ # Mix-in to store property values in instance variables of the same name.
15
+ #
16
+ module NRSER::Props::Immutable::InstanceVariables
17
+
18
+ STORAGE = NRSER::Props::Storage::InstanceVariables.new immutable: true
19
+
20
+
21
+ # Class Methods
22
+ # ======================================================================
23
+
24
+ def self.included base
25
+ base.include NRSER::Props
26
+ base.metadata.storage STORAGE
27
+ base.metadata.freeze
28
+ end
29
+
30
+
31
+ # Instance Methods
32
+ # ======================================================================
33
+
34
+ # Since the {NRSER::Props::Immutable::InstanceVariables} mix-in does *not*
35
+ # need to tap into the initialize chain,
36
+ #
37
+ def initialize_props values = {}
38
+ self.class.metadata.each_primary_prop_value_from( values ) { |prop, value|
39
+ instance_variable_set "@#{ prop.name }", value
40
+ }
41
+
42
+ # Check additional type invariants
43
+ self.class.invariants.each do |type|
44
+ type.check self
45
+ end
46
+ end # #initialize_props
47
+
48
+ end # module NRSER::Props::Immutable
@@ -0,0 +1,107 @@
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
3
+
4
+ # Requirements
5
+ # =======================================================================
6
+
7
+ # Deps
8
+ # -----------------------------------------------------------------------
9
+ require 'hamster'
10
+
11
+ # Project / Package
12
+ # -----------------------------------------------------------------------
13
+ require_relative '../storage/key'
14
+
15
+
16
+ # Declarations
17
+ # =======================================================================
18
+
19
+ module NRSER::Props::Immutable; end
20
+
21
+
22
+ # Definitions
23
+ # =======================================================================
24
+
25
+ # Mixin for classes that extend {Hamster::Vector} and will use itself as the
26
+ # property value storage, requiring that property keys be non-negative
27
+ # integers.
28
+ #
29
+ module NRSER::Props::Immutable::Vector
30
+
31
+ # Constants
32
+ # ==========================================================================
33
+
34
+ STORAGE = NRSER::Props::Storage::Key.new immutable: true, key_type: :index
35
+
36
+
37
+ # Module Methods
38
+ # ======================================================================
39
+
40
+ def self.included base
41
+ unless base < Hamster::Vector
42
+ raise binding.erb <<~END
43
+ This class is only for including in {Hamster::Vector} subclasses!
44
+ END
45
+ end
46
+
47
+ base.include NRSER::Props
48
+ base.metadata.storage STORAGE
49
+ base.metadata.freeze
50
+
51
+ base.extend ClassMethods
52
+ end
53
+
54
+
55
+ # Mixin Methods
56
+ # ======================================================================
57
+
58
+ # Methods mixed in at the class-level.
59
+ #
60
+ module ClassMethods
61
+ # {Hamster::Vector} uses `.alloc` to quickly create derived instances
62
+ # when it knows the instance variables. We need to hook into that to
63
+ # check the prop types.
64
+ #
65
+ # @param (see Hamster::Vector.alloc)
66
+ #
67
+ # @return [Hamster::Vector]
68
+ # The new instance, which will be of the propertied subclass of
69
+ # {Hamster::Vector}.
70
+ #
71
+ # @raise [TypeError]
72
+ # If the prop values of the new vector don't satisfy the prop types.
73
+ #
74
+ def alloc *args
75
+ super( *args ).tap do |new_instance|
76
+ self.props( only_primary: true ).each_value do |prop|
77
+ prop.check! new_instance[prop.index]
78
+ end
79
+ end
80
+ end
81
+ end # module ClassMethods
82
+
83
+
84
+ # Constructor
85
+ # ----------------------------------------------------------------------------
86
+
87
+ # Since including classes are using themselves as storage, we need to tap
88
+ # into the `#initialize` chain in order to load property values from sources
89
+ # and pass an {Array} up to the super-method to instantiate the
90
+ # {Hamster::Vector}.
91
+ #
92
+ def initialize values = {}
93
+ super_values = []
94
+
95
+ self.class.metadata.each_primary_prop_value_from( values ) { |prop, value|
96
+ super_values[prop.index] = value
97
+ }
98
+
99
+ super super_values
100
+
101
+ # Check additional type invariants
102
+ self.class.invariants.each do |type|
103
+ type.check self
104
+ end
105
+ end # #initialize
106
+
107
+ end # module NRSER::Props::Immutable::Vector