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.
- checksums.yaml +4 -4
- data/README.md +39 -11
- data/lib/nrser.rb +5 -1
- data/lib/nrser/array.rb +10 -53
- data/lib/nrser/enumerable.rb +21 -0
- data/lib/nrser/hash.rb +13 -476
- data/lib/nrser/hash/bury.rb +154 -0
- data/lib/nrser/hash/deep_merge.rb +57 -0
- data/lib/nrser/hash/except_keys.rb +42 -0
- data/lib/nrser/hash/guess_label_key_type.rb +37 -0
- data/lib/nrser/hash/slice_keys.rb +41 -0
- data/lib/nrser/hash/stringify_keys.rb +37 -0
- data/lib/nrser/hash/symbolize_keys.rb +41 -0
- data/lib/nrser/hash/transform_keys.rb +45 -0
- data/lib/nrser/merge_by.rb +26 -0
- data/lib/nrser/message.rb +125 -0
- data/lib/nrser/meta/props.rb +2 -2
- data/lib/nrser/meta/props/prop.rb +5 -2
- data/lib/nrser/object.rb +5 -0
- data/lib/nrser/object/as_array.rb +37 -0
- data/lib/nrser/object/as_hash.rb +101 -0
- data/lib/nrser/{truthy.rb → object/truthy.rb} +0 -0
- data/lib/nrser/proc.rb +132 -0
- data/lib/nrser/refinements.rb +1 -2
- data/lib/nrser/refinements/array.rb +94 -5
- data/lib/nrser/refinements/enumerable.rb +5 -0
- data/lib/nrser/refinements/hash.rb +43 -6
- data/lib/nrser/refinements/object.rb +22 -2
- data/lib/nrser/refinements/symbol.rb +12 -0
- data/lib/nrser/refinements/tree.rb +41 -0
- data/lib/nrser/rspex.rb +329 -0
- data/lib/nrser/string.rb +3 -0
- data/lib/nrser/string/looks_like.rb +51 -0
- data/lib/nrser/temp/where.rb +52 -0
- data/lib/nrser/tree.rb +86 -0
- data/lib/nrser/tree/leaves.rb +92 -0
- data/lib/nrser/tree/map_leaves.rb +63 -0
- data/lib/nrser/tree/transform.rb +30 -0
- data/lib/nrser/types.rb +9 -4
- data/lib/nrser/types/any.rb +1 -1
- data/lib/nrser/types/array.rb +167 -25
- data/lib/nrser/types/{hash.rb → hashes.rb} +19 -5
- data/lib/nrser/types/in.rb +47 -0
- data/lib/nrser/types/is_a.rb +2 -2
- data/lib/nrser/types/labels.rb +49 -0
- data/lib/nrser/types/numbers.rb +63 -27
- data/lib/nrser/types/pairs.rb +109 -0
- data/lib/nrser/types/responds.rb +2 -3
- data/lib/nrser/types/strings.rb +17 -18
- data/lib/nrser/types/symbols.rb +39 -0
- data/lib/nrser/types/trees.rb +93 -0
- data/lib/nrser/types/tuples.rb +116 -0
- data/lib/nrser/types/type.rb +26 -2
- data/lib/nrser/version.rb +1 -1
- data/spec/nrser/hash/{guess_name_type_spec.rb → guess_label_key_type_spec.rb} +3 -3
- data/spec/nrser/hash_spec.rb +0 -20
- data/spec/nrser/merge_by_spec.rb +73 -0
- data/spec/nrser/meta/props_spec.rb +136 -43
- data/spec/nrser/op/message_spec.rb +62 -0
- data/spec/nrser/refinements/array_spec.rb +36 -0
- data/spec/nrser/refinements/hash_spec.rb +34 -0
- data/spec/nrser/string/looks_like_spec.rb +31 -0
- data/spec/nrser/tree/each_branch_spec.rb +82 -0
- data/spec/nrser/tree/leaves_spec.rb +112 -0
- data/spec/nrser/tree/transform_spec.rb +165 -0
- data/spec/nrser/types/array_spec.rb +82 -0
- data/spec/nrser/types/attrs_spec.rb +4 -4
- data/spec/nrser/types/pairs_spec.rb +41 -0
- data/spec/nrser/types/paths_spec.rb +3 -3
- data/spec/nrser/types/strings_spec.rb +66 -0
- data/spec/nrser/types/symbols_spec.rb +38 -0
- data/spec/nrser/types/tuples_spec.rb +37 -0
- data/spec/nrser/types_spec.rb +0 -13
- data/spec/spec_helper.rb +71 -22
- metadata +58 -10
- data/lib/nrser/spex.rb +0 -68
- 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
|
+
|
data/lib/nrser/meta/props.rb
CHANGED
@@ -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.
|
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
|
data/lib/nrser/object.rb
ADDED
@@ -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
|