nrser 0.0.30 → 0.1.0

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