nrser 0.0.25 → 0.0.26

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 (77) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +39 -11
  3. data/lib/nrser.rb +5 -1
  4. data/lib/nrser/array.rb +10 -53
  5. data/lib/nrser/enumerable.rb +21 -0
  6. data/lib/nrser/hash.rb +13 -476
  7. data/lib/nrser/hash/bury.rb +154 -0
  8. data/lib/nrser/hash/deep_merge.rb +57 -0
  9. data/lib/nrser/hash/except_keys.rb +42 -0
  10. data/lib/nrser/hash/guess_label_key_type.rb +37 -0
  11. data/lib/nrser/hash/slice_keys.rb +41 -0
  12. data/lib/nrser/hash/stringify_keys.rb +37 -0
  13. data/lib/nrser/hash/symbolize_keys.rb +41 -0
  14. data/lib/nrser/hash/transform_keys.rb +45 -0
  15. data/lib/nrser/merge_by.rb +26 -0
  16. data/lib/nrser/message.rb +125 -0
  17. data/lib/nrser/meta/props.rb +2 -2
  18. data/lib/nrser/meta/props/prop.rb +5 -2
  19. data/lib/nrser/object.rb +5 -0
  20. data/lib/nrser/object/as_array.rb +37 -0
  21. data/lib/nrser/object/as_hash.rb +101 -0
  22. data/lib/nrser/{truthy.rb → object/truthy.rb} +0 -0
  23. data/lib/nrser/proc.rb +132 -0
  24. data/lib/nrser/refinements.rb +1 -2
  25. data/lib/nrser/refinements/array.rb +94 -5
  26. data/lib/nrser/refinements/enumerable.rb +5 -0
  27. data/lib/nrser/refinements/hash.rb +43 -6
  28. data/lib/nrser/refinements/object.rb +22 -2
  29. data/lib/nrser/refinements/symbol.rb +12 -0
  30. data/lib/nrser/refinements/tree.rb +41 -0
  31. data/lib/nrser/rspex.rb +329 -0
  32. data/lib/nrser/string.rb +3 -0
  33. data/lib/nrser/string/looks_like.rb +51 -0
  34. data/lib/nrser/temp/where.rb +52 -0
  35. data/lib/nrser/tree.rb +86 -0
  36. data/lib/nrser/tree/leaves.rb +92 -0
  37. data/lib/nrser/tree/map_leaves.rb +63 -0
  38. data/lib/nrser/tree/transform.rb +30 -0
  39. data/lib/nrser/types.rb +9 -4
  40. data/lib/nrser/types/any.rb +1 -1
  41. data/lib/nrser/types/array.rb +167 -25
  42. data/lib/nrser/types/{hash.rb → hashes.rb} +19 -5
  43. data/lib/nrser/types/in.rb +47 -0
  44. data/lib/nrser/types/is_a.rb +2 -2
  45. data/lib/nrser/types/labels.rb +49 -0
  46. data/lib/nrser/types/numbers.rb +63 -27
  47. data/lib/nrser/types/pairs.rb +109 -0
  48. data/lib/nrser/types/responds.rb +2 -3
  49. data/lib/nrser/types/strings.rb +17 -18
  50. data/lib/nrser/types/symbols.rb +39 -0
  51. data/lib/nrser/types/trees.rb +93 -0
  52. data/lib/nrser/types/tuples.rb +116 -0
  53. data/lib/nrser/types/type.rb +26 -2
  54. data/lib/nrser/version.rb +1 -1
  55. data/spec/nrser/hash/{guess_name_type_spec.rb → guess_label_key_type_spec.rb} +3 -3
  56. data/spec/nrser/hash_spec.rb +0 -20
  57. data/spec/nrser/merge_by_spec.rb +73 -0
  58. data/spec/nrser/meta/props_spec.rb +136 -43
  59. data/spec/nrser/op/message_spec.rb +62 -0
  60. data/spec/nrser/refinements/array_spec.rb +36 -0
  61. data/spec/nrser/refinements/hash_spec.rb +34 -0
  62. data/spec/nrser/string/looks_like_spec.rb +31 -0
  63. data/spec/nrser/tree/each_branch_spec.rb +82 -0
  64. data/spec/nrser/tree/leaves_spec.rb +112 -0
  65. data/spec/nrser/tree/transform_spec.rb +165 -0
  66. data/spec/nrser/types/array_spec.rb +82 -0
  67. data/spec/nrser/types/attrs_spec.rb +4 -4
  68. data/spec/nrser/types/pairs_spec.rb +41 -0
  69. data/spec/nrser/types/paths_spec.rb +3 -3
  70. data/spec/nrser/types/strings_spec.rb +66 -0
  71. data/spec/nrser/types/symbols_spec.rb +38 -0
  72. data/spec/nrser/types/tuples_spec.rb +37 -0
  73. data/spec/nrser/types_spec.rb +0 -13
  74. data/spec/spec_helper.rb +71 -22
  75. metadata +58 -10
  76. data/lib/nrser/spex.rb +0 -68
  77. data/lib/nrser/types/symbol.rb +0 -23
@@ -0,0 +1,154 @@
1
+ # Definitions
2
+ # =======================================================================
3
+
4
+ module NRSER
5
+
6
+ # Eigenclass (Singleton Class)
7
+ # ========================================================================
8
+ #
9
+ class << self
10
+
11
+ # The opposite of `#dig` - set a value at a deep key path, creating
12
+ # necessary structures along the way and optionally clobbering whatever's
13
+ # in the way to achieve success.
14
+ #
15
+ # @param [Hash] hash
16
+ # Hash to bury the value in.
17
+ #
18
+ # @param [Array | #to_s] key_path
19
+ # - When an {Array}, each entry is used exactly as-is for each key.
20
+ #
21
+ # - Otherwise, the `key_path` is converted to a string and split by
22
+ # `.` to produce the key array, and the actual keys used depend on
23
+ # the `parsed_key_type` option.
24
+ #
25
+ # @param [Object] value
26
+ # The value to set at the end of the path.
27
+ #
28
+ # @param [Class | :guess] parsed_key_type:
29
+ # How to handle parsed key path segments:
30
+ #
31
+ # - `String` - use the strings that naturally split from a parsed
32
+ # key path.
33
+ #
34
+ # Note that this is the *String class itself, **not** a value that
35
+ # is a String*.
36
+ #
37
+ # - `Symbol` - convert the strings that are split from the key path
38
+ # to symbols.
39
+ #
40
+ # Note that this is the *Symbol class itself, **not** a value that
41
+ # is a Symbol*.``
42
+ #
43
+ # - `:guess` (default) -
44
+ #
45
+ # @return [return_type]
46
+ # @todo Document return value.
47
+ #
48
+ def bury! hash,
49
+ key_path,
50
+ value,
51
+ parsed_key_type: :guess,
52
+ clobber: false,
53
+ create_arrays_for_unsigned_keys: false
54
+
55
+ # Parse the key if it's not an array
56
+ unless key_path.is_a?( Array )
57
+ key_path = key_path.to_s.split '.'
58
+
59
+ # Convert the keys to symbols now if that's what we want to use
60
+ if parsed_key_type == Symbol
61
+ key_path.map! &:to_sym
62
+ end
63
+ end
64
+
65
+ _internal_bury! \
66
+ hash,
67
+ key_path,
68
+ value,
69
+ guess_key_type: ( parsed_key_type == :guess ),
70
+ clobber: clobber,
71
+ create_arrays_for_unsigned_keys: create_arrays_for_unsigned_keys
72
+ end # #bury
73
+
74
+
75
+ private
76
+ # ========================================================================
77
+
78
+
79
+ # @todo Document _internal_bury! method.
80
+ #
81
+ # @param [type] arg_name
82
+ # @todo Add name param description.
83
+ #
84
+ # @return [return_type]
85
+ # @todo Document return value.
86
+ #
87
+ def _internal_bury! tree,
88
+ key_path,
89
+ value,
90
+ guess_key_type:,
91
+ clobber:,
92
+ create_arrays_for_unsigned_keys:
93
+
94
+ # Split the key path into the current key and the rest of the keys
95
+ key, *rest = key_path
96
+
97
+ # If we are
98
+ #
99
+ # - Guessing the key type
100
+ # - The tree is keyed
101
+ # - The tree uses some {Symbol} (and no {String}) keys
102
+ #
103
+ # then convert the key to a symbol.
104
+ #
105
+ if guess_key_type &&
106
+ tree.respond_to?( :keys ) &&
107
+ guess_label_key_type( tree ) == Symbol
108
+ key = key.to_sym
109
+ end
110
+
111
+ # Terminating case: we're at the last segment
112
+ if rest.empty?
113
+ # Set the value
114
+ tree[key] = value
115
+
116
+ else
117
+ # Go deeper...
118
+
119
+ # See if there is a hash in place
120
+ unless NRSER::Types.tree.test tree[key]
121
+ # There is not... so we need to do some figurin'
122
+
123
+ # If we're clobbering or the hash has no value, we're good:
124
+ # assign a new hash to set in
125
+ if clobber || tree[key].nil?
126
+ if create_arrays_for_unsigned_keys &&
127
+ NRSER::Types.unsigned.test( key )
128
+ tree[key] = []
129
+ else
130
+ tree[key] = {}
131
+ end
132
+
133
+ else
134
+ # We've got an intractable state conflict; raise
135
+ raise NRSER::ConflictError.new squish <<-END
136
+ can not set key #{ key.inspect } due to conflicting value
137
+ #{ tree[key].inspect } in tree #{ tree.inspect } (:clobber
138
+ option not set)
139
+ END
140
+
141
+ end
142
+ end # unless hash[key].is_a?( Hash )
143
+
144
+ # Dive in...
145
+ bury! tree[key], rest, value
146
+
147
+ end # if rest.empty? / else
148
+ end # #_internal_bury!
149
+
150
+ # end private
151
+
152
+ end # class << self (Eigenclass)
153
+
154
+ end # module NRSER
@@ -0,0 +1,57 @@
1
+
2
+ # Definitions
3
+ # =======================================================================
4
+
5
+ module NRSER
6
+
7
+ # Returns a new hash created by recursively merging `other_hash` on top of
8
+ # `base_hash`.
9
+ #
10
+ # Adapted from ActiveSupport.
11
+ #
12
+ # @see https://github.com/rails/rails/blob/23c8f6918d4e6b9a823aa7a91377c6e3b5d60e13/activesupport/lib/active_support/core_ext/hash/deep_merge.rb
13
+ #
14
+ # @param [Hash] base_hash
15
+ # Base hash - it's values will be overwritten by any key paths shared with
16
+ # the other hash.
17
+ #
18
+ # @param [Hash] other_hash
19
+ # "Update" hash - it's values will overwrite values at the same key path
20
+ # in the base hash.
21
+ #
22
+ # I don't love the name; just went with what ActiveSupport used.
23
+ #
24
+ # @return [Hash]
25
+ # New merged hash.
26
+ #
27
+ def self.deep_merge base_hash, other_hash, &block
28
+ deep_merge! base_hash.dup, other_hash, &block
29
+ end # .deep_merge
30
+
31
+
32
+ # Same as {.deep_merge}, but modifies `base_hash`.
33
+ #
34
+ # @return [Hash]
35
+ # The mutated base hash.
36
+ #
37
+ def self.deep_merge! base_hash, other_hash, &block
38
+ other_hash.each_pair do |current_key, other_value|
39
+ this_value = base_hash[current_key]
40
+
41
+ base_hash[current_key] = if this_value.is_a?(Hash) &&
42
+ other_value.is_a?(Hash)
43
+ deep_merge this_value, other_value, &block
44
+ else
45
+ if block_given? && key?(current_key)
46
+ block.call(current_key, this_value, other_value)
47
+ else
48
+ other_value
49
+ end
50
+ end
51
+ end
52
+
53
+ base_hash
54
+ end
55
+
56
+
57
+ end # module NRSER
@@ -0,0 +1,42 @@
1
+ # Definitions
2
+ # =======================================================================
3
+
4
+ module NRSER
5
+
6
+ # Removes the given keys from hash and returns it.
7
+ #
8
+ # Lifted from ActiveSupport.
9
+ #
10
+ # @see http://www.rubydoc.info/gems/activesupport/5.1.3/Hash:except!
11
+ #
12
+ # @param [Hash] hash
13
+ # Hash to mutate.
14
+ #
15
+ # @return [Hash]
16
+ #
17
+ def self.except_keys! hash, *keys
18
+ keys.each { |key| hash.delete(key) }
19
+ hash
20
+ end
21
+
22
+ singleton_class.send :alias_method, :omit_keys!, :except_keys!
23
+
24
+
25
+ # Returns a new hash without `keys`.
26
+ #
27
+ # Lifted from ActiveSupport.
28
+ #
29
+ # @see http://www.rubydoc.info/gems/activesupport/5.1.3/Hash:except
30
+ #
31
+ # @param [Hash] hash
32
+ # Source hash.
33
+ #
34
+ # @return [Hash]
35
+ #
36
+ def self.except_keys hash, *keys
37
+ except_keys! hash.dup, *keys
38
+ end
39
+
40
+ singleton_class.send :alias_method, :omit_keys, :except_keys
41
+
42
+ end # module NRSER
@@ -0,0 +1,37 @@
1
+ # Definitions
2
+ # =======================================================================
3
+
4
+ module NRSER
5
+
6
+ # Guess which type of "label" key - strings or symbols - a hash (or other
7
+ # object that responds to `#keys` and `#empty`) uses.
8
+ #
9
+ # @param [#keys & #empty] keyed
10
+ # Hash or similar object that responds to `#keys` and `#empty` to guess
11
+ # about.
12
+ #
13
+ # @return [nil]
14
+ # If we can't determine the type of "label" keys are used (there aren't
15
+ # any or there is a mix).
16
+ #
17
+ # @return [Class]
18
+ # If we can determine that {String} or {Symbol} keys are exclusively
19
+ # used returns that class.
20
+ #
21
+ def self.guess_label_key_type keyed
22
+ # We can't tell shit if the hash is empty
23
+ return nil if keyed.empty?
24
+
25
+ name_types = keyed.
26
+ keys.
27
+ map( &:class ).
28
+ select { |klass| klass == String || klass == Symbol }.
29
+ uniq
30
+
31
+ return name_types[0] if name_types.length == 1
32
+
33
+ # There are both string and symbol keys present, we can't guess
34
+ nil
35
+ end # .guess_label_key_type
36
+
37
+ end # module NRSER
@@ -0,0 +1,41 @@
1
+ # Definitions
2
+ # =======================================================================
3
+
4
+ module NRSER
5
+
6
+ # Lifted from ActiveSupport.
7
+ #
8
+ # @see http://www.rubydoc.info/gems/activesupport/5.1.3/Hash:slice
9
+ #
10
+ #
11
+ def self.slice_keys hash, *keys
12
+ # We're not using this, but, whatever, leave it in...
13
+ if hash.respond_to?(:convert_key, true)
14
+ keys.map! { |key| hash.send :convert_key, key }
15
+ end
16
+
17
+ keys.each_with_object(hash.class.new) { |k, new_hash|
18
+ new_hash[k] = hash[k] if hash.has_key?(k)
19
+ }
20
+ end
21
+
22
+
23
+ # Meant to be a drop-in replacement for the ActiveSupport version, though
24
+ # I've changed the implementation a bit... because honestly I didn't
25
+ # understand why they were doing it the way they do :/
26
+ #
27
+ # @see http://www.rubydoc.info/gems/activesupport/5.1.3/Hash:slice!
28
+ #
29
+ #
30
+ def self.slice_keys! hash, *keys
31
+ # We're not using this, but, whatever, leave it in...
32
+ if hash.respond_to?(:convert_key, true)
33
+ keys.map! { |key| hash.send :convert_key, key }
34
+ end
35
+
36
+ slice_keys( hash, *keys ).tap { |slice|
37
+ except_keys! hash, *keys
38
+ }
39
+ end
40
+
41
+ end # module NRSER
@@ -0,0 +1,37 @@
1
+ # Definitions
2
+ # =======================================================================
3
+
4
+ module NRSER
5
+
6
+ # Converts all keys into strings by calling `#to_s` on them. **Mutates the
7
+ # hash.**
8
+ #
9
+ # Lifted from ActiveSupport.
10
+ #
11
+ # @param [Hash] hash
12
+ #
13
+ # @return [Hash<String, *>]
14
+ #
15
+ def self.stringify_keys! hash
16
+ transform_keys! hash, &:to_s
17
+ end
18
+
19
+ singleton_class.send :alias_method, :str_keys!, :stringify_keys!
20
+
21
+
22
+ # Returns a new hash with all keys transformed to strings by calling `#to_s`
23
+ # on them.
24
+ #
25
+ # Lifted from ActiveSupport.
26
+ #
27
+ # @param [Hash] hash
28
+ #
29
+ # @return [Hash<String, *>]
30
+ #
31
+ def self.stringify_keys hash
32
+ transform_keys hash, &:to_s
33
+ end
34
+
35
+ singleton_class.send :alias_method, :str_keys, :stringify_keys
36
+
37
+ end # module NRSER
@@ -0,0 +1,41 @@
1
+ # Definitions
2
+ # =======================================================================
3
+
4
+ module NRSER
5
+
6
+ # Mutates `hash` by converting all keys that respond to `#to_sym` to symbols.
7
+ #
8
+ # Lifted from ActiveSupport.
9
+ #
10
+ # @see http://www.rubydoc.info/gems/activesupport/5.1.3/Hash:symbolize_keys!
11
+ #
12
+ # @param [Hash] hash
13
+ #
14
+ # @return [Hash]
15
+ #
16
+ def self.symbolize_keys! hash
17
+ transform_keys!(hash) { |key| key.to_sym rescue key }
18
+ end # .symbolize_keys!
19
+
20
+ singleton_class.send :alias_method, :sym_keys!, :symbolize_keys!
21
+
22
+
23
+ # Returns a new hash with all keys that respond to `#to_sym` converted to
24
+ # symbols.
25
+ #
26
+ # Lifted from ActiveSupport.
27
+ #
28
+ # @see http://www.rubydoc.info/gems/activesupport/5.1.3/Hash:symbolize_keys
29
+ #
30
+ # @param [Hash] hash
31
+ #
32
+ # @return [Hash]
33
+ #
34
+ def self.symbolize_keys hash
35
+ # File 'lib/active_support/core_ext/hash/keys.rb', line 54
36
+ transform_keys(hash) { |key| key.to_sym rescue key }
37
+ end
38
+
39
+ singleton_class.send :alias_method, :sym_keys, :symbolize_keys
40
+
41
+ end # module NRSER
@@ -0,0 +1,45 @@
1
+ module NRSER
2
+
3
+ # Lifted from ActiveSupport.
4
+ #
5
+ # @see http://www.rubydoc.info/gems/activesupport/5.1.3/Hash:transform_keys!
6
+ #
7
+ # @param [Hash] hash
8
+ # Hash to mutate keys.
9
+ #
10
+ # @return [Hash]
11
+ # The mutated hash.
12
+ #
13
+ def self.transform_keys! hash
14
+ # File 'lib/active_support/core_ext/hash/keys.rb', line 23
15
+ hash.keys.each do |key|
16
+ hash[yield(key)] = hash.delete(key)
17
+ end
18
+ hash
19
+ end
20
+
21
+
22
+ # Returns a new hash with each key transformed by the provided block.
23
+ #
24
+ # Lifted from ActiveSupport.
25
+ #
26
+ # @see http://www.rubydoc.info/gems/activesupport/5.1.3/Hash:transform_keys
27
+ #
28
+ # @param [Hash] hash
29
+ #
30
+ # @return [Hash]
31
+ # New hash with transformed keys.
32
+ #
33
+ def self.transform_keys hash, &block
34
+ # File 'lib/active_support/core_ext/hash/keys.rb', line 12
35
+ result = {}
36
+ hash.each_key do |key|
37
+ result[yield(key)] = hash[key]
38
+ end
39
+ result
40
+ end
41
+
42
+ # My-style name
43
+ singleton_class.send :alias_method, :map_keys, :transform_keys
44
+
45
+ end # module NRSER