nrser 0.0.25 → 0.0.26

Sign up to get free protection for your applications and to get access to all the features.
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