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,26 @@
1
+
2
+
3
+ module NRSER
4
+
5
+ # Eigenclass (Singleton Class)
6
+ # ========================================================================
7
+ #
8
+ class << self
9
+
10
+ # @todo Document merge_by method.
11
+ #
12
+ # @param [type] arg_name
13
+ # @todo Add name param description.
14
+ #
15
+ # @return [return_type]
16
+ # @todo Document return value.
17
+ #
18
+ def merge_by current, *updates, &getter
19
+ updates.reduce( to_h_by current, &getter ) { |result, update|
20
+ deep_merge! result, to_h_by(update, &getter)
21
+ }.values
22
+ end # #merge_by
23
+
24
+ end # class << self (Eigenclass)
25
+
26
+ end # module NRSER
@@ -0,0 +1,125 @@
1
+ # Definitions
2
+ # =======================================================================
3
+
4
+ module NRSER
5
+
6
+ # Container for a message (method call) to be sent to a receiver via
7
+ # {Object#send} (or {Object#public_send}).
8
+ #
9
+ # Encapsulates the method symbol as well as any arguments and block to send.
10
+ #
11
+ # Implements `#to_proc` so it can be used like
12
+ #
13
+ # enum.map &message
14
+ #
15
+ # You can invoke the message on a receiver object like
16
+ #
17
+ # msg.send_to obj
18
+ #
19
+ # Useful for clearly describing and recognizing data that is meant to be
20
+ # sent to an object as a method call, especially in testing.
21
+ #
22
+ class Message
23
+ # Name of method the message is for.
24
+ #
25
+ # @return [Symbol | String]
26
+ #
27
+ attr_reader :symbol
28
+
29
+
30
+ # Arguments (parameters). May be empty.
31
+ #
32
+ # @return [Array]
33
+ #
34
+ attr_reader :args
35
+
36
+
37
+ # Optional block to send to the receiver.
38
+ #
39
+ # @return [nil | #call]
40
+ #
41
+ attr_reader :block
42
+
43
+
44
+ # Construct a new message.
45
+ #
46
+ # @param [String | Symbol] symbol
47
+ # Name of target method.
48
+ #
49
+ # @param [Array] *args
50
+ # Any arguments that should be sent.
51
+ #
52
+ # @param [nil | #call] &block
53
+ # Optional block that should be sent.
54
+ #
55
+ def initialize symbol, *args, &block
56
+ @symbol = symbol
57
+ @args = args
58
+ @block = block
59
+ end
60
+
61
+
62
+ # Creates a {Proc} that accepts a single `receiver` argument and calls
63
+ # {#sent_to} on it, allowing messages to be used via the `&` operator
64
+ # in `map`, etc.
65
+ #
66
+ # @example Map each entry as the message receiver using `&`
67
+ #
68
+ # enum = [ [], [1], [1, 2] ]
69
+ #
70
+ # length_message = NRSER::Message.new :length
71
+ # first_message = NRSER::Message.new :first
72
+ #
73
+ # enum.map &length_message
74
+ # # => [0, 1, 2]
75
+ #
76
+ # enum.map &first_message
77
+ # # => [nil, 1, 1]
78
+ #
79
+ # @return [Proc]
80
+ #
81
+ def to_proc publicly: true
82
+ # block
83
+ ->( receiver ) { send_to receiver, publicly: publicly }
84
+ end
85
+
86
+ alias_method :to_sender, :to_proc
87
+
88
+
89
+ # Send this instance to a receiver object.
90
+ #
91
+ # @example
92
+ #
93
+ # msg.send_to obj
94
+ #
95
+ # @param [Object] receiver
96
+ # Object that the message will be sent to.
97
+ #
98
+ # @param [Boolean] publicly:
99
+ # When `true`, the message will be sent via {Object#public_send}. This is
100
+ # the default behavior.
101
+ #
102
+ # When `false`, the message will be sent via {Object#send}, allowing it
103
+ # to invoke private and protected methods on the receiver.
104
+ #
105
+ # @return [Object]
106
+ # Result of the method call.
107
+ #
108
+ def send_to receiver, publicly: true
109
+ if publicly
110
+ receiver.public_send symbol, *args, &block
111
+ else
112
+ receiver.send symbol, *args, &block
113
+ end
114
+ end
115
+
116
+ # @return [String]
117
+ # Brief description of the message.
118
+ #
119
+ def to_s
120
+ "#<NRSER::Message symbol=#{ symbol } args=#{ args } block=#{ block }>"
121
+ end
122
+ end # class Message
123
+
124
+ end # module NRSER
125
+
@@ -217,7 +217,8 @@ module Props
217
217
  # @todo Document return value.
218
218
  #
219
219
  def to_h only_own: false, only_primary: false
220
- self.class.props(only_own: only_own, only_primary: only_primary).
220
+ self.class.
221
+ props(only_own: only_own, only_primary: only_primary).
221
222
  map_values { |name, prop| prop.get self }
222
223
  end # #to_h
223
224
 
@@ -251,7 +252,6 @@ module Props
251
252
  end # #to_data
252
253
 
253
254
 
254
-
255
255
  # Language Inter-Op
256
256
  # ---------------------------------------------------------------------
257
257
 
@@ -154,7 +154,6 @@ class Prop
154
154
  end # #set
155
155
 
156
156
 
157
-
158
157
  # @todo Document set_from_hash method.
159
158
  #
160
159
  # @param [type] arg_name
@@ -168,7 +167,11 @@ class Prop
168
167
  set instance, values[name]
169
168
  else
170
169
  if default?
171
- set instance, default.dup
170
+ set instance, if !default.nil? && default.respond_to?( :dup )
171
+ default.dup
172
+ else
173
+ default
174
+ end
172
175
  else
173
176
  raise TypeError.new NRSER.squish <<-END
174
177
  Prop #{ name } has no default value and no value was provided in
@@ -0,0 +1,5 @@
1
+ # Require all the individual `//lib/object` files...
2
+ #
3
+ require_relative './object/truthy'
4
+ require_relative './object/as_hash'
5
+ require_relative './object/as_array'
@@ -0,0 +1,37 @@
1
+ module NRSER
2
+
3
+ # Return an array given any value in the way that makes most sense:
4
+ #
5
+ # 1. If `value` is an array, return it.
6
+ #
7
+ # 2. If `value` is `nil`, return `[]`.
8
+ #
9
+ # 3. If `value` responds to `#to_a`, try calling it. If it succeeds, return
10
+ # that.
11
+ #
12
+ # 4. Return an array with `value` as it's only item.
13
+ #
14
+ # Refinement
15
+ # ----------
16
+ #
17
+ # Added to `Object` in `nrser/refinements`.
18
+ #
19
+ # @param [Object] value
20
+ #
21
+ # @return [Array]
22
+ #
23
+ def self.as_array value
24
+ return value if value.is_a? Array
25
+ return [] if value.nil?
26
+
27
+ if value.respond_to? :to_a
28
+ begin
29
+ return value.to_a
30
+ rescue
31
+ end
32
+ end
33
+
34
+ [value]
35
+ end # .as_array
36
+
37
+ end # module NRSER
@@ -0,0 +1,101 @@
1
+ module NRSER
2
+
3
+ # Treat the value as the value for `key` in a hash if it's not already a
4
+ # hash and can't be converted to one:
5
+ #
6
+ # 1. If the value is a `Hash`, return it.
7
+ #
8
+ # 2. If `value` is `nil`, return `{}`.
9
+ #
10
+ # 3. If the value responds to `#to_h` and `#to_h` succeeds, return the
11
+ # resulting hash.
12
+ #
13
+ # 4. Otherwise, return a new hash where `key` points to the value.
14
+ # **`key` MUST be provided in this case.**
15
+ #
16
+ # Useful in method overloading and similar situations where you expect a
17
+ # hash that may specify a host of options, but want to allow the method
18
+ # to be called with a single value that corresponds to a default key in that
19
+ # option hash.
20
+ #
21
+ # Refinement
22
+ # ----------
23
+ #
24
+ # Added to `Object` in `nrser/refinements`.
25
+ #
26
+ #
27
+ # Example Time!
28
+ # -------------
29
+ #
30
+ # Say you have a method `m` that handles a hash of HTML options that can
31
+ # look something like
32
+ #
33
+ # {class: 'address', data: {confirm: 'Really?'}}
34
+ #
35
+ # And can call `m` like
36
+ #
37
+ # m({class: 'address', data: {confirm: 'Really?'}})
38
+ #
39
+ # but often you are just dealing with the `:class` option. You can use
40
+ # {NRSER.as_hash} to accept a string and treat it as the `:class` key:
41
+ #
42
+ # using NRSER
43
+ #
44
+ # def m opts
45
+ # opts = opts.as_hash :class
46
+ # # ...
47
+ # end
48
+ #
49
+ # If you pass a hash, everything works normally, but if you pass a string
50
+ # `'address'` it will be converted to `{class: 'address'}`.
51
+ #
52
+ #
53
+ # About `#to_h` Support
54
+ # ---------------------
55
+ #
56
+ # Right now, {.as_hash} also tests if `value` responds to `#to_h`, and will
57
+ # try to call it, using the result if it doesn't raise. This lets it deal
58
+ # with Ruby's "I used to be a Hash until someone mapped me" values like
59
+ # `[[:class, 'address']]`. I'm not sure if this is the best approach, but
60
+ # I'm going to try it for now and see how it pans out in actual usage.
61
+ #
62
+ # @todo
63
+ # It might be nice to have a `check` option that ensures the resulting
64
+ # hash has a value for `key`.
65
+ #
66
+ # @param [Object] value
67
+ # The value that we want to be a hash.
68
+ #
69
+ # @param [Object] key [default nil]
70
+ # The key that `value` will be stored under in the result if `value` is
71
+ # not a hash or can't be turned into one via `#to_h`. If this happens
72
+ # this value can **NOT** be `nil` or an `ArgumentError` is raised.
73
+ #
74
+ # @return [Hash]
75
+ #
76
+ # @raise [ArgumentError]
77
+ # If it comes to constructing a new Hash with `value` as a value and no
78
+ # argument was provided
79
+ #
80
+ def self.as_hash value, key = nil
81
+ return value if value.is_a? Hash
82
+ return {} if value.nil?
83
+
84
+ if value.respond_to? :to_h
85
+ begin
86
+ return value.to_h
87
+ rescue
88
+ end
89
+ end
90
+
91
+ # at this point we need a key argument
92
+ if key.nil?
93
+ raise ArgumentError,
94
+ "Need key to construct hash with value #{ value.inspect }, " +
95
+ "found nil."
96
+ end
97
+
98
+ {key => value}
99
+ end # .as_hash
100
+
101
+ end # module NRSER
File without changes
data/lib/nrser/proc.rb ADDED
@@ -0,0 +1,132 @@
1
+ ##
2
+ # Methods that make useful {Proc} instances.
3
+ ##
4
+
5
+ # Requirements
6
+ # =======================================================================
7
+
8
+ # Stdlib
9
+ # -----------------------------------------------------------------------
10
+
11
+ # Deps
12
+ # -----------------------------------------------------------------------
13
+
14
+ # Project / Package
15
+ # -----------------------------------------------------------------------
16
+ require_relative './message'
17
+
18
+
19
+ # Definitions
20
+ # =======================================================================
21
+
22
+ module NRSER
23
+
24
+ # Creates a new {NRSER::Message} from the array.
25
+ #
26
+ # @example
27
+ #
28
+ # message = NRSER::Op.message( :fetch, :x )
29
+ # message.send_to x: 'ex', y: 'why?'
30
+ # # => 'ex'
31
+ #
32
+ # @return [NRSER::Message]
33
+ #
34
+ def self.message symbol, *args, &block
35
+ NRSER::Message.new symbol, *args, &block
36
+ end # #message
37
+
38
+ singleton_class.send :alias_method, :msg, :message
39
+
40
+
41
+ # Create a {Proc} that sends the arguments to a receiver via `#public_send`.
42
+ #
43
+ # Equivalent to
44
+ #
45
+ # message( symbol, *args, &block ).to_proc
46
+ #
47
+ # Pretty much here for completeness' sake.
48
+ #
49
+ # @example
50
+ #
51
+ # sender( :fetch, :x ).call x: 'ex'
52
+ # # => 'ex'
53
+ #
54
+ # @return [Proc]
55
+ #
56
+ def self.public_sender symbol, *args, &block
57
+ message( symbol, *args, &block ).to_proc
58
+ end # .public_sender
59
+
60
+ singleton_class.send :alias_method, :sender, :public_sender
61
+ singleton_class.send :alias_method, :sndr, :public_sender
62
+
63
+
64
+ # Create a {Proc} that sends the arguments to a receiver via `#send`,
65
+ # forcing access to private and protected methods.
66
+ #
67
+ # Equivalent to
68
+ #
69
+ # message( symbol, *args, &block ).to_proc publicly: false
70
+ #
71
+ # Pretty much here for completeness' sake.
72
+ #
73
+ # @example
74
+ #
75
+ # sender( :fetch, :x ).call x: 'ex'
76
+ # # => 'ex'
77
+ #
78
+ # @return [Proc]
79
+ #
80
+ def self.private_sender symbol, *args, &block
81
+ message( symbol, *args, &block ).to_proc publicly: false
82
+ end # .private_sender
83
+
84
+
85
+ # Map *each entry* in `mappable` to a {NRSER::Message} and return a
86
+ # {Proc} that accepts a single `receiver` argument and reduces it by
87
+ # applying each message in turn.
88
+ #
89
+ # In less precise terms: create a proc that chains the entries as
90
+ # methods calls.
91
+ #
92
+ # @note
93
+ # `mappable`` entries are mapped into messages when {#to_chain} is called,
94
+ # meaning subsequent changes to `mappable` **will not** affect the
95
+ # returned proc.
96
+ #
97
+ # @example Equivalent of `Time.now.to_i`
98
+ #
99
+ # NRSER::chainer( [:now, :to_i] ).call Time
100
+ # # => 1509628038
101
+ #
102
+ # @return [Proc]
103
+ #
104
+ def self.chainer mappable, publicly: true
105
+ messages = mappable.map { |value| NRSER::Message.new *value }
106
+
107
+ ->( receiver ) {
108
+ messages.reduce( receiver ) { |receiver, message|
109
+ message.send_to receiver, publicly: publicly
110
+ }
111
+ }
112
+ end # .chainer
113
+
114
+ singleton_class.send :alias_method, :chnr, :chainer
115
+
116
+
117
+ # Return a {Proc} that accepts a single argument that must respond to `#[]`
118
+ # and retrieves `key` from it.
119
+ #
120
+ # @param [String | Symbol | Integer] key
121
+ # Key (or index) to retrieve.
122
+ #
123
+ # @return [Proc]
124
+ #
125
+ def self.retriever key
126
+ ->( indexed ) { indexed[key] }
127
+ end # .getter
128
+
129
+ singleton_class.send :alias_method, :rtvr, :retriever
130
+
131
+
132
+ end # module NRSER