nrser 0.0.30 → 0.1.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 (107) hide show
  1. checksums.yaml +4 -4
  2. data/lib/nrser.rb +56 -12
  3. data/lib/nrser/collection.rb +4 -7
  4. data/lib/nrser/ext.rb +5 -0
  5. data/lib/nrser/{refinements → ext}/enumerable.rb +11 -9
  6. data/lib/nrser/ext/pathname.rb +74 -0
  7. data/lib/nrser/{refinements → ext}/tree.rb +2 -26
  8. data/lib/nrser/functions.rb +18 -0
  9. data/lib/nrser/{array.rb → functions/array.rb} +2 -3
  10. data/lib/nrser/{binding.rb → functions/binding.rb} +0 -2
  11. data/lib/nrser/functions/enumerable.rb +355 -0
  12. data/lib/nrser/functions/enumerable/find_all_map.rb +33 -0
  13. data/lib/nrser/functions/enumerable/find_map.rb +53 -0
  14. data/lib/nrser/functions/exception.rb +17 -0
  15. data/lib/nrser/{hash.rb → functions/hash.rb} +0 -0
  16. data/lib/nrser/functions/hash/bury.rb +147 -0
  17. data/lib/nrser/{hash → functions/hash}/deep_merge.rb +5 -5
  18. data/lib/nrser/{hash → functions/hash}/except_keys.rb +2 -0
  19. data/lib/nrser/{hash → functions/hash}/guess_label_key_type.rb +3 -1
  20. data/lib/nrser/{hash → functions/hash}/slice_keys.rb +3 -1
  21. data/lib/nrser/{hash → functions/hash}/stringify_keys.rb +2 -0
  22. data/lib/nrser/{hash → functions/hash}/symbolize_keys.rb +3 -1
  23. data/lib/nrser/{hash → functions/hash}/transform_keys.rb +3 -1
  24. data/lib/nrser/functions/merge_by.rb +29 -0
  25. data/lib/nrser/{object.rb → functions/object.rb} +0 -0
  26. data/lib/nrser/{object → functions/object}/as_array.rb +2 -0
  27. data/lib/nrser/{object → functions/object}/as_hash.rb +7 -5
  28. data/lib/nrser/{object → functions/object}/truthy.rb +46 -7
  29. data/lib/nrser/{open_struct.rb → functions/open_struct.rb} +0 -0
  30. data/lib/nrser/functions/path.rb +150 -0
  31. data/lib/nrser/{proc.rb → functions/proc.rb} +1 -22
  32. data/lib/nrser/functions/string.rb +297 -0
  33. data/lib/nrser/functions/string/looks_like.rb +44 -0
  34. data/lib/nrser/{text.rb → functions/text.rb} +0 -0
  35. data/lib/nrser/{text → functions/text}/indentation.rb +2 -16
  36. data/lib/nrser/{text → functions/text}/lines.rb +1 -2
  37. data/lib/nrser/{text → functions/text}/word_wrap.rb +2 -4
  38. data/lib/nrser/{tree.rb → functions/tree.rb} +0 -0
  39. data/lib/nrser/{tree → functions/tree}/each_branch.rb +6 -7
  40. data/lib/nrser/functions/tree/leaves.rb +92 -0
  41. data/lib/nrser/{tree → functions/tree}/map_branches.rb +31 -32
  42. data/lib/nrser/functions/tree/map_leaves.rb +56 -0
  43. data/lib/nrser/{tree → functions/tree}/map_tree.rb +9 -20
  44. data/lib/nrser/{tree → functions/tree}/transform.rb +0 -10
  45. data/lib/nrser/logger.rb +9 -10
  46. data/lib/nrser/message.rb +3 -7
  47. data/lib/nrser/meta.rb +2 -0
  48. data/lib/nrser/meta/class_attrs.rb +3 -9
  49. data/lib/nrser/meta/props.rb +19 -19
  50. data/lib/nrser/meta/props/base.rb +4 -10
  51. data/lib/nrser/meta/props/prop.rb +12 -28
  52. data/lib/nrser/no_arg.rb +1 -3
  53. data/lib/nrser/refinements.rb +5 -0
  54. data/lib/nrser/refinements/array.rb +5 -17
  55. data/lib/nrser/refinements/enumerator.rb +1 -3
  56. data/lib/nrser/refinements/hash.rb +3 -15
  57. data/lib/nrser/refinements/object.rb +2 -2
  58. data/lib/nrser/refinements/open_struct.rb +0 -2
  59. data/lib/nrser/refinements/pathname.rb +3 -46
  60. data/lib/nrser/refinements/set.rb +2 -6
  61. data/lib/nrser/refinements/string.rb +2 -2
  62. data/lib/nrser/rspex.rb +16 -13
  63. data/lib/nrser/types.rb +6 -20
  64. data/lib/nrser/types/any.rb +0 -1
  65. data/lib/nrser/types/booleans.rb +1 -1
  66. data/lib/nrser/types/combinators.rb +5 -5
  67. data/lib/nrser/types/in.rb +0 -21
  68. data/lib/nrser/types/responds.rb +1 -0
  69. data/lib/nrser/types/trees.rb +1 -0
  70. data/lib/nrser/version.rb +2 -3
  71. data/spec/nrser/{template_spec.rb → functions/binding/template_spec.rb} +0 -0
  72. data/spec/nrser/functions/enumerable/find_all_map_spec.rb +28 -0
  73. data/spec/nrser/functions/enumerable/find_bounded_spec.rb +70 -0
  74. data/spec/nrser/functions/enumerable/find_map_spec.rb +38 -0
  75. data/spec/nrser/functions/enumerable/find_only_spec.rb +25 -0
  76. data/spec/nrser/functions/enumerable/to_h_by_spec.rb +28 -0
  77. data/spec/nrser/{format_exception_spec.rb → functions/exception/format_exception_spec.rb} +0 -0
  78. data/spec/nrser/{hash → functions/hash}/bury_spec.rb +0 -0
  79. data/spec/nrser/{hash → functions/hash}/guess_label_key_type_spec.rb +0 -0
  80. data/spec/nrser/{hash_spec.rb → functions/hash_spec.rb} +0 -7
  81. data/spec/nrser/{merge_by_spec.rb → functions/merge_by_spec.rb} +0 -0
  82. data/spec/nrser/{truthy_spec.rb → functions/object/truthy_spec.rb} +0 -0
  83. data/spec/nrser/{open_struct_spec.rb → functions/open_struct_spec.rb} +0 -0
  84. data/spec/nrser/{string → functions/string}/common_prefix_spec.rb +0 -0
  85. data/spec/nrser/{string → functions/string}/looks_like_spec.rb +0 -0
  86. data/spec/nrser/{truncate_spec.rb → functions/string/truncate_spec.rb} +0 -0
  87. data/spec/nrser/{text → functions/text}/dedent/gotchas_spec.rb +0 -0
  88. data/spec/nrser/{text → functions/text}/dedent_spec.rb +0 -0
  89. data/spec/nrser/{indent_spec.rb → functions/text/indent_spec.rb} +0 -0
  90. data/spec/nrser/{tree → functions/tree}/each_branch_spec.rb +0 -0
  91. data/spec/nrser/{tree → functions/tree}/leaves_spec.rb +0 -0
  92. data/spec/nrser/{tree → functions/tree}/map_branch_spec.rb +0 -0
  93. data/spec/nrser/{tree → functions/tree}/map_tree_spec.rb +0 -0
  94. data/spec/nrser/{tree → functions/tree}/transform_spec.rb +0 -0
  95. data/spec/nrser/{tree → functions/tree}/transformer_spec.rb +0 -0
  96. data/spec/nrser/meta/class_attrs_spec.rb +12 -14
  97. data/spec/spec_helper.rb +2 -3
  98. metadata +136 -110
  99. data/lib/nrser/enumerable.rb +0 -288
  100. data/lib/nrser/exception.rb +0 -7
  101. data/lib/nrser/hash/bury.rb +0 -154
  102. data/lib/nrser/merge_by.rb +0 -26
  103. data/lib/nrser/string.rb +0 -294
  104. data/lib/nrser/string/looks_like.rb +0 -51
  105. data/lib/nrser/tree/leaves.rb +0 -92
  106. data/lib/nrser/tree/map_leaves.rb +0 -63
  107. data/spec/nrser/enumerable_spec.rb +0 -111
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # Functional methods that try to tell what format a string that
5
+ # is presumed to encode structural data is encoded in.
6
+ ##
7
+
8
+
9
+ # Definitions
10
+ # =======================================================================
11
+
12
+ module NRSER
13
+
14
+ # @!group String Functions
15
+
16
+ # Constants
17
+ # =====================================================================
18
+
19
+ # Regexp used to guess if a string is a JSON-encoded array.
20
+ #
21
+ # @return [Regexp]
22
+ #
23
+ JSON_ARRAY_RE = /\A\s*\[.*\]\s*\z/m.freeze
24
+
25
+
26
+ # Functions
27
+ # ============================================================================
28
+
29
+
30
+ # Test if a string looks like it might encode an array in JSON format by
31
+ # seeing if it's first non-whitespace character is `[` and last
32
+ # non-whitespace character is `]`.
33
+ #
34
+ # @param [String] string
35
+ # String to test.
36
+ #
37
+ # @return [Boolean]
38
+ # `true` if we think `string` encodes a JSON array.
39
+ #
40
+ def self.looks_like_json_array? string
41
+ !!( string =~ JSON_ARRAY_RE )
42
+ end # #looks_like_json_array
43
+
44
+ end # module NRSER
File without changes
@@ -1,19 +1,5 @@
1
- # Requirements
2
- # =======================================================================
3
-
4
- # Stdlib
5
- # -----------------------------------------------------------------------
6
-
7
- # Deps
8
- # -----------------------------------------------------------------------
9
-
10
- # Project / Package
11
- # -----------------------------------------------------------------------
12
- require_relative './lines'
13
-
14
-
15
1
  module NRSER
16
- # @!group Text
2
+ # @!group Text Functions
17
3
 
18
4
 
19
5
  # Constants
@@ -109,7 +95,7 @@ module NRSER
109
95
  # `marker` and `separator` can be configured via keyword arguments, but they
110
96
  # default to:
111
97
  #
112
- # - `marker` - {NRSER::INDENT_TAG_MARKER}, the no-printable ASCII
98
+ # - `marker` - {NRSER::INDENT_TAG_MARKER}, the no-printable ASCII
113
99
  # *record separator* (ASCII character 30, "\x1E" / "\u001E").
114
100
  #
115
101
  # - `separator` - {NRSER::INDENT_TAG_SEPARATOR}, the non-printable ASCII
@@ -1,6 +1,5 @@
1
-
2
1
  module NRSER
3
- # @!group Text
2
+ # @!group Text Functions
4
3
 
5
4
  # Classes
6
5
  # =====================================================================
@@ -1,6 +1,5 @@
1
-
2
1
  module NRSER
3
- # @!group Text
2
+ # @!group Text Functions
4
3
 
5
4
  # Split text at whitespace to fit in line length. Lifted from Rails'
6
5
  # ActionView.
@@ -24,6 +23,5 @@ module NRSER
24
23
  line.length > line_width ? line.gsub(/(.{1,#{line_width}})(\s+|$)/, "\\1#{break_sequence}").strip : line
25
24
  end * break_sequence
26
25
  end # .word_wrap
27
-
28
-
26
+
29
27
  end # module NRSER
File without changes
@@ -1,8 +1,7 @@
1
- # Definitions
2
- # =======================================================================
3
-
4
1
  module NRSER
5
2
 
3
+ # @!group Tree Functions
4
+
6
5
  # Enumerate over the immediate "branches" of a structure that can be used
7
6
  # to compose our idea of a *tree*: nested hash-like and array-like structures
8
7
  # like you would get from parsing a JSON document.
@@ -35,7 +34,7 @@ module NRSER
35
34
  # `#each_with_index` call.
36
35
  #
37
36
  # @raise [NoMethodError]
38
- # If `tree` does not respond to `#each_pair` or to `#each_index` and
37
+ # If `tree` does not respond to `#each_pair` or to `#each_index` and
39
38
  # `#each_with_index`.
40
39
  #
41
40
  def self.each_branch tree, &block
@@ -44,13 +43,13 @@ module NRSER
44
43
  tree.each_pair &block
45
44
 
46
45
  elsif tree.respond_to? :each_index
47
- # Array-like... we test for `each_index` because - unintuitively -
46
+ # Array-like... we test for `each_index` because - unintuitively -
48
47
  # `#each_with_index` is a method of {Enumerable}, meaning that {Set}
49
48
  # responds to it, though sets are unordered and the values can't be
50
- # accessed via those indexes. Hence we look for `#each_index`, which
49
+ # accessed via those indexes. Hence we look for `#each_index`, which
51
50
  # {Set} does not respond to.
52
51
 
53
- if block.nil?
52
+ if block.nil?
54
53
  index_enumerator = tree.each_with_index
55
54
 
56
55
  Enumerator.new( index_enumerator.size ) { |yielder|
@@ -0,0 +1,92 @@
1
+ module NRSER
2
+
3
+ # @!group Tree Functions
4
+
5
+ # Create a new hash where all the values are the scalar "leaves" of the
6
+ # possibly nested `hash` param. Leaves are keyed by "key path" arrays
7
+ # representing the sequence of keys to dig that leaf out of the has param.
8
+ #
9
+ # In abstract, if `h` is the `hash` param and
10
+ #
11
+ # l = NRSER.leaves h
12
+ #
13
+ # then for each key `k` and corresponding value `v` in `l`
14
+ #
15
+ # h.dig( *k ) == v
16
+ #
17
+ # @pure
18
+ # Return value depends only on parameters.
19
+ #
20
+ # @example Simple "flat" hash
21
+ #
22
+ # NRSER.leaves( {a: 1, b: 2} )
23
+ # => {
24
+ # [:a] => 1,
25
+ # [:b] => 2,
26
+ # }
27
+ #
28
+ # @example Nested hash
29
+ #
30
+ # NRSER.leaves(
31
+ # 1 => {
32
+ # name: 'Neil',
33
+ # fav_color: 'blue',
34
+ # },
35
+ # 2 => {
36
+ # name: 'Mica',
37
+ # fav_color: 'red',
38
+ # }
39
+ # )
40
+ # # => {
41
+ # # [1, :name] => 'Neil',
42
+ # # [1, :fav_color] => 'blue',
43
+ # # [2, :name] => 'Mica',
44
+ # # [2, :fav_color] => 'red',
45
+ # # }
46
+ #
47
+ # @param [#each_pair | (#each_index & #each_with_index)] tree
48
+ #
49
+ # @return [Hash<Array, Object>]
50
+ #
51
+ def self.leaves tree
52
+ {}.tap { |results|
53
+ _internal_leaves tree, path: [], results: results
54
+ }
55
+ end # .leaves
56
+
57
+
58
+ # Internal recursive implementation for {NRSER.leaves}.
59
+ #
60
+ # @private
61
+ #
62
+ # @pure
63
+ # Return value depends only on parameters.
64
+ #
65
+ # @param [#each_pair | (#each_index & #each_with_index)] tree
66
+ # Tree to walk.
67
+ #
68
+ # @param [Array] path
69
+ # Key path down to `tree`.
70
+ #
71
+ # @param [Hash<Array, Object>] results
72
+ # New hash to stick results in.
73
+ #
74
+ # @return [nil]
75
+ #
76
+ def self._internal_leaves tree, path:, results:
77
+ NRSER.each_branch( tree ) { |key, value|
78
+ new_path = [*path, key]
79
+
80
+ if NRSER::Types.tree.test value
81
+ _internal_leaves value, path: new_path, results: results
82
+ else
83
+ results[new_path] = value
84
+ end
85
+ }
86
+
87
+ nil
88
+ end # ._internal_leaves
89
+
90
+ private_class_method :_internal_leaves
91
+
92
+ end # module NRSER
@@ -1,18 +1,7 @@
1
- # Requirements
2
- # =======================================================================
3
-
4
- # Project / Package
5
- # -----------------------------------------------------------------------
6
- require 'nrser/types/trees'
7
-
8
- require_relative './each_branch'
9
-
10
-
11
- # Definitions
12
- # =======================================================================
13
-
14
1
  module NRSER
15
2
 
3
+ # @!group Tree Functions
4
+
16
5
  # Map the immediate "branches" of a structure that can be used
17
6
  # to compose our idea of a *tree*: nested hash-like and array-like structures
18
7
  # like you would get from parsing a JSON document.
@@ -20,8 +9,8 @@ module NRSER
20
9
  # The `block` **MUST** return a pair ({Array} of length 2), the first value
21
10
  # of which is the key or index in the new {Hash} or {Array}.
22
11
  #
23
- # These pairs are then converted into a {Hash} or {Array} depending on it
24
- # `tree` was {NRSER::Types.hash_like} or {NRSER::Types.array_like}, and
12
+ # These pairs are then converted into a {Hash} or {Array} depending on it
13
+ # `tree` was {NRSER::Types.hash_like} or {NRSER::Types.array_like}, and
25
14
  # that value is returned.
26
15
  #
27
16
  # Uses {NRSER.each_branch} internally.
@@ -34,20 +23,20 @@ module NRSER
34
23
  # 2. *array-like* that responds to `#each_index` and `#each_with_index`
35
24
  # appropriately.
36
25
  #
37
- # @note Not sure what will happen if the tree has circular references!
26
+ # @pure
27
+ # Return value depends only on parameters.
28
+ #
29
+ # @note
30
+ # Not sure what will happen if the tree has circular references!
38
31
  #
39
32
  # @todo
40
33
  # Might be nice to have an option to preserve the tree class that creates
41
- # a new instance of *whatever* it was and populates that, though I could
34
+ # a new instance of *whatever* it was and populates that, though I could
42
35
  # see this relying on problematic assumptions and producing confusing
43
36
  # results depending on the actual classes.
44
37
  #
45
38
  # Maybe this could be encoded in a mixin that we would detect or something.
46
39
  #
47
- # @example
48
- #
49
- #
50
- #
51
40
  # @param [#each_pair | (#each_index & #each_with_index)] tree
52
41
  # Structure representing a tree via hash-like and array-like containers.
53
42
  #
@@ -65,10 +54,13 @@ module NRSER
65
54
  # @return [Array | Hash]
66
55
  # If no block is provided.
67
56
  #
68
- # @raise [NoMethodError]
69
- # If `tree` does not respond to `#each_pair` or to `#each_index` and
57
+ # @raise [TypeError | NoMethodError]
58
+ # If `tree` does not respond to `#each_pair` or to `#each_index` and
70
59
  # `#each_with_index`.
71
60
  #
61
+ # @raise [ArgumentError]
62
+ # If `&block` is not provided.
63
+ #
72
64
  def self.map_branches tree, &block
73
65
  if block.nil?
74
66
  raise ArgumentError, "Must provide block"
@@ -76,16 +68,23 @@ module NRSER
76
68
 
77
69
  pairs = each_branch( tree ).map &block
78
70
 
79
- Types.match tree,
80
- Types.hash_like, ->( _ ) {
81
- pairs.to_h
82
- },
83
-
84
- Types.array_like, ->( _ ) {
85
- pairs.each_with_object( [] ) { |(index, value), array|
86
- array[index] = value
87
- }
71
+ if hash_like? tree
72
+ pairs.to_h
73
+ elsif array_like? tree
74
+ pairs.each_with_object( [] ) { |(index, value), array|
75
+ array[index] = value
88
76
  }
77
+ else
78
+ raise TypeError.new erb binding, <<-END
79
+ Excepted `tree` arg to be array or hash-like.
80
+
81
+ Received (<%= tree.class %>):
82
+
83
+ <%= tree.pretty_inspect %>
84
+
85
+ END
86
+ end
87
+
89
88
  end # .map_branches
90
89
 
91
90
  end # module NRSER
@@ -0,0 +1,56 @@
1
+ module NRSER
2
+
3
+ # @!group Tree Functions
4
+
5
+ def self.map_leaves tree, &block
6
+ NRSER::Types.tree.check tree
7
+
8
+ _internal_map_leaves tree, key_path: [], &block
9
+ end # #map_leaves
10
+
11
+
12
+ # Internal recursive implementation for {NRSER.leaves}.
13
+ #
14
+ # @param [#each_pair | (#each_index & #each_with_index)] tree
15
+ # Tree to walk.
16
+ #
17
+ # @param [Array] path
18
+ # Key path down to `tree`.
19
+ #
20
+ # @param [Hash<Array, Object>] results
21
+ # New hash to stick results in.
22
+ #
23
+ # @return [nil]
24
+ #
25
+ def self._internal_map_leaves tree, key_path:, &block
26
+ NRSER::Types.match tree,
27
+ NRSER::Types.hash_like, ->( hash_like ) {
28
+ hash_like.map { |key, value|
29
+ new_key_path = [*key_path, key]
30
+
31
+ new_value = if NRSER::Types.tree.test( value )
32
+ _internal_map_leaves value, key_path: new_key_path, &block
33
+ else
34
+ block.call new_key_path, value
35
+ end
36
+
37
+ [key, new_value]
38
+ }.to_h
39
+ },
40
+
41
+ NRSER::Types.array_like, ->( array_like ) {
42
+ array_like.each_with_index.map { |value, index|
43
+ new_key_path = [*key_path, index]
44
+
45
+ if NRSER::Types.tree.test( value )
46
+ _internal_map_leaves value, key_path: new_key_path, &block
47
+ else
48
+ block.call new_key_path, value
49
+ end
50
+ }
51
+ }
52
+ end # #_internal_leaves
53
+
54
+ private_class_method :_internal_map_leaves
55
+
56
+ end # module NRSER
@@ -1,31 +1,20 @@
1
- # Requirements
2
- # =======================================================================
3
-
4
- # Project / Package
5
- # -----------------------------------------------------------------------
6
- require_relative './map_branches'
7
-
8
-
9
- # Definitions
10
- # =======================================================================
11
-
12
1
  module NRSER
13
2
  # Recursively descend through a tree mapping *all* non-structural elements
14
3
  # - anything not {NRSER::Types.hash_like} or {NRSER::Types.array_like}, both
15
- # hash keys *and* values, as well as array entries - through `block` to
4
+ # hash keys *and* values, as well as array entries - through `block` to
16
5
  # produce a new structure.
17
6
  #
18
7
  # Useful when you want to translate pieces of a tree structure depending on
19
- # their type or some other property that can be determined *from the element
20
- # alone* - `block` receives only the value as an argument, no location
8
+ # their type or some other property that can be determined *from the element
9
+ # alone* - `block` receives only the value as an argument, no location
21
10
  # information (because it's weirder to represent for keys and I didn't need
22
11
  # it for the {NRSER.transformer} stuff this was written for).
23
12
  #
24
13
  # @note
25
14
  # Array indexes **are not mapped** through `block` and can not be changed
26
- # via this method. This makes it easier to do things like "convert all the
27
- # integers to strings" when you mean the data entries, not the array
28
- # indexes (which would fail since the new array wouldn't accept string
15
+ # via this method. This makes it easier to do things like "convert all the
16
+ # integers to strings" when you mean the data entries, not the array
17
+ # indexes (which would fail since the new array wouldn't accept string
29
18
  # indices).
30
19
  #
31
20
  # If you don't want to map hash keys use {NRSER.map_leaves}.
@@ -40,7 +29,7 @@ module NRSER
40
29
  #
41
30
  # @yieldparam [Object] element
42
31
  # Anything reached from the root that is not structural (hash-like or
43
- # array-like), including / inside hash keys (though array
32
+ # array-like), including / inside hash keys (though array
44
33
  # indexes are **not** passed).
45
34
  #
46
35
  def self.map_tree tree, prune: false, &block
@@ -49,7 +38,7 @@ module NRSER
49
38
  mapped = tree.map { |element|
50
39
  # Recur if `element` is a tree.
51
40
  #
52
- # Since `element` will be an {Array} of `key`, `value` when `tree` is a
41
+ # Since `element` will be an {Array} of `key`, `value` when `tree` is a
53
42
  # {Hash} (or similar), this will descend into hash keys that are also
54
43
  # trees, as well as into hash values and array entries.
55
44
  #
@@ -61,7 +50,7 @@ module NRSER
61
50
  end
62
51
  }
63
52
 
64
- # If `tree` is hash-like, we want to convert the array of pair arrays
53
+ # If `tree` is hash-like, we want to convert the array of pair arrays
65
54
  # back into a hash.
66
55
  if Types.hash_like.test tree
67
56
  if prune