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,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