accessory 0.1.5 → 0.1.6
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/lib/accessory.rb +5 -2
- data/lib/accessory/access.rb +16 -1
- data/lib/accessory/accessor.rb +30 -37
- data/lib/accessory/accessors/all_accessor.rb +7 -3
- data/lib/accessory/accessors/attribute_accessor.rb +7 -5
- data/lib/accessory/accessors/between_each_accessor.rb +10 -6
- data/lib/accessory/accessors/betwixt_accessor.rb +23 -14
- data/lib/accessory/accessors/filter_accessor.rb +7 -3
- data/lib/accessory/accessors/first_accessor.rb +9 -5
- data/lib/accessory/accessors/instance_variable_accessor.rb +6 -6
- data/lib/accessory/accessors/last_accessor.rb +9 -5
- data/lib/accessory/accessors/subscript_accessor.rb +12 -7
- data/lib/accessory/bound_lens.rb +139 -0
- data/lib/accessory/lens.rb +192 -75
- data/lib/accessory/traversal_position/enumerable_before_offset.rb +5 -5
- data/lib/accessory/version.rb +1 -1
- metadata +3 -3
- data/lib/accessory/lens_path.rb +0 -219
@@ -9,22 +9,22 @@ module Accessory::TraversalPosition; end
|
|
9
9
|
#
|
10
10
|
# * An +EnumerableBeforeOffset+ with an <tt>.offset</tt> of <tt>0</tt>
|
11
11
|
# represents the position directly before the first result from
|
12
|
-
# <tt>#each</tt>, i.e. "the beginning." Using {
|
12
|
+
# <tt>#each</tt>, i.e. "the beginning." Using {Lens#put_in} at this position
|
13
13
|
# will _prepend_ to the +Enumerable+.
|
14
14
|
#
|
15
15
|
# * An +EnumerableBeforeOffset+ with an <tt>.offset</tt> equal to the
|
16
16
|
# <tt>#length</tt> of the +Enumerable+ (recognizable by
|
17
17
|
# <tt>EnumerableBeforeOffset#last?</tt> returning +true+) represents
|
18
18
|
# represents the position directly before the end of the enumeration,
|
19
|
-
# i.e. "the end" of the +Enumerable+. Using {
|
19
|
+
# i.e. "the end" of the +Enumerable+. Using {Lens#put_in} at this position
|
20
20
|
# will _append_ to the +Enumerable+.
|
21
21
|
#
|
22
|
-
# * In general, using {
|
22
|
+
# * In general, using {Lens#put_in} with an +EnumerableBeforeOffset+ with an
|
23
23
|
# <tt>.offset</tt> of +n+ will insert an element _between_ elements
|
24
24
|
# <tt>n - 1</tt> and +n+ in the enumeration sequence.
|
25
25
|
#
|
26
|
-
# * Returning <tt>:pop</tt> from {
|
27
|
-
# +EnumerableBeforeOffset+-terminated {
|
26
|
+
# * Returning <tt>:pop</tt> from {Lens#get_and_update_in} for an
|
27
|
+
# +EnumerableBeforeOffset+-terminated {Lens} will have no effect, as
|
28
28
|
# you're removing an empty slice.
|
29
29
|
|
30
30
|
class Accessory::TraversalPosition::EnumerableBeforeOffset
|
data/lib/accessory/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: accessory
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Levi Aul
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-01-
|
11
|
+
date: 2021-01-13 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description:
|
14
14
|
email:
|
@@ -29,8 +29,8 @@ files:
|
|
29
29
|
- lib/accessory/accessors/instance_variable_accessor.rb
|
30
30
|
- lib/accessory/accessors/last_accessor.rb
|
31
31
|
- lib/accessory/accessors/subscript_accessor.rb
|
32
|
+
- lib/accessory/bound_lens.rb
|
32
33
|
- lib/accessory/lens.rb
|
33
|
-
- lib/accessory/lens_path.rb
|
34
34
|
- lib/accessory/traversal_position/enumerable_at_offset.rb
|
35
35
|
- lib/accessory/traversal_position/enumerable_before_offset.rb
|
36
36
|
- lib/accessory/version.rb
|
data/lib/accessory/lens_path.rb
DELETED
@@ -1,219 +0,0 @@
|
|
1
|
-
module Accessory; end
|
2
|
-
|
3
|
-
require 'accessory/accessor'
|
4
|
-
require 'accessory/accessors/subscript_accessor'
|
5
|
-
|
6
|
-
class Accessory::LensPath
|
7
|
-
# Returns the empty (identity) LensPath.
|
8
|
-
# @return [LensPath] the empty (identity) LensPath.
|
9
|
-
def self.empty
|
10
|
-
@empty_lens_path ||= (new([]).freeze)
|
11
|
-
end
|
12
|
-
|
13
|
-
# Returns a {LensPath} containing the specified +accessors+.
|
14
|
-
# @return [LensPath] a LensPath containing the specified +accessors+.
|
15
|
-
def self.[](*accessors)
|
16
|
-
new(accessors).freeze
|
17
|
-
end
|
18
|
-
|
19
|
-
class << self
|
20
|
-
private :new
|
21
|
-
end
|
22
|
-
|
23
|
-
# @!visibility private
|
24
|
-
def initialize(initial_parts)
|
25
|
-
@parts = []
|
26
|
-
|
27
|
-
for part in initial_parts
|
28
|
-
append_accessor!(part)
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
# @!visibility private
|
33
|
-
def to_a
|
34
|
-
@parts
|
35
|
-
end
|
36
|
-
|
37
|
-
# @!visibility private
|
38
|
-
def inspect(format: :long)
|
39
|
-
parts_desc = @parts.map{ |part| part.inspect(format: :short) }.join(', ')
|
40
|
-
parts_desc = "[#{parts_desc}]"
|
41
|
-
|
42
|
-
case format
|
43
|
-
when :long
|
44
|
-
"#LensPath#{parts_desc}"
|
45
|
-
when :short
|
46
|
-
parts_desc
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
# Returns a new {LensPath} resulting from appending +accessor+ to the receiver.
|
51
|
-
# @param accessor [Object] the accessor to append
|
52
|
-
# @return [LensPath] the new joined LensPath
|
53
|
-
def then(accessor)
|
54
|
-
d = self.dup
|
55
|
-
d.append_accessor!(accessor)
|
56
|
-
d.freeze
|
57
|
-
end
|
58
|
-
|
59
|
-
# @!visibility private
|
60
|
-
def dup
|
61
|
-
d = super
|
62
|
-
d.instance_eval do
|
63
|
-
@parts = @parts.dup
|
64
|
-
end
|
65
|
-
d
|
66
|
-
end
|
67
|
-
|
68
|
-
# Returns a new {LensPath} resulting from concatenating +other+ to the end
|
69
|
-
# of the receiver.
|
70
|
-
# @param other [Object] an accessor, an +Array+ of accessors, or another LensPath
|
71
|
-
# @return [LensPath] the new joined LensPath
|
72
|
-
def +(other)
|
73
|
-
parts =
|
74
|
-
case other
|
75
|
-
when Accessory::LensPath
|
76
|
-
other.to_a
|
77
|
-
when Array
|
78
|
-
other
|
79
|
-
else
|
80
|
-
[other]
|
81
|
-
end
|
82
|
-
|
83
|
-
d = self.dup
|
84
|
-
for part in parts
|
85
|
-
d.append_accessor!(part)
|
86
|
-
end
|
87
|
-
d.freeze
|
88
|
-
end
|
89
|
-
|
90
|
-
alias_method :/, :+
|
91
|
-
|
92
|
-
# Traverses +subject+ using the chain of accessors held in this LensPath,
|
93
|
-
# returning the discovered value.
|
94
|
-
#
|
95
|
-
# *Equivalent* in Elixir: {https://hexdocs.pm/elixir/Kernel.html#get_in/2 +Kernel.get_in/2+}
|
96
|
-
#
|
97
|
-
# @return [Object] the value found after all traversals.
|
98
|
-
def get_in(subject)
|
99
|
-
if @parts.empty?
|
100
|
-
subject
|
101
|
-
else
|
102
|
-
get_in_step(subject, @parts)
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
|
-
# Traverses +subject+ using the chain of accessors held in this LensPath,
|
107
|
-
# modifying the final value at the end of the traversal chain using
|
108
|
-
# the passed +mutator_fn+, and returning the original targeted value(s)
|
109
|
-
# pre-modification.
|
110
|
-
#
|
111
|
-
# +mutator_fn+ must return one of two data "shapes":
|
112
|
-
# * a two-element +Array+, representing:
|
113
|
-
# 1. the value to surface as the "get" value of the traversal
|
114
|
-
# 2. the new value to replace at the traversal-position
|
115
|
-
# * the Symbol +:pop+ — which will remove the value from its parent, and
|
116
|
-
# return it as-is.
|
117
|
-
#
|
118
|
-
# *Equivalent* in Elixir: {https://hexdocs.pm/elixir/Kernel.html#get_and_update_in/3 +Kernel.get_and_update_in/3+}
|
119
|
-
#
|
120
|
-
# @param subject [Object] the data-structure to traverse
|
121
|
-
# @param mutator_fn [Proc] a block taking the original value derived from
|
122
|
-
# traversing +subject+, and returning a modification operation.
|
123
|
-
# @return [Array] a two-element +Array+, consisting of
|
124
|
-
# 1. the _old_ value(s) found after all traversals, and
|
125
|
-
# 2. the updated +subject+
|
126
|
-
def get_and_update_in(subject, &mutator_fn)
|
127
|
-
if @parts.empty?
|
128
|
-
subject
|
129
|
-
else
|
130
|
-
get_and_update_in_step(subject, @parts, mutator_fn)
|
131
|
-
end
|
132
|
-
end
|
133
|
-
|
134
|
-
# Traverses +subject+ using the chain of accessors held in this LensPath,
|
135
|
-
# replacing the final value at the end of the traversal chain with the
|
136
|
-
# result from the passed +new_value_fn+.
|
137
|
-
#
|
138
|
-
# *Equivalent* in Elixir: {https://hexdocs.pm/elixir/Kernel.html#update_in/3 +Kernel.update_in/3+}
|
139
|
-
#
|
140
|
-
# @param subject [Object] the data-structure to traverse
|
141
|
-
# @param new_value_fn [Proc] a block taking the original value derived from
|
142
|
-
# traversing +subject+, and returning a replacement value.
|
143
|
-
# @return [Array] a two-element +Array+, consisting of
|
144
|
-
# 1. the _old_ value(s) found after all traversals, and
|
145
|
-
# 2. the updated +subject+
|
146
|
-
def update_in(subject, &new_value_fn)
|
147
|
-
_, new_data = self.get_and_update_in(data){ |v| [nil, new_value_fn.call(v)] }
|
148
|
-
new_data
|
149
|
-
end
|
150
|
-
|
151
|
-
# Traverses +subject+ using the chain of accessors held in this LensPath,
|
152
|
-
# replacing the final value at the end of the traversal chain with
|
153
|
-
# +new_value+.
|
154
|
-
#
|
155
|
-
# *Equivalent* in Elixir: {https://hexdocs.pm/elixir/Kernel.html#put_in/3 +Kernel.put_in/3+}
|
156
|
-
#
|
157
|
-
# @param subject [Object] the data-structure to traverse
|
158
|
-
# @param new_value [Object] a replacement value at the traversal position.
|
159
|
-
# @return [Object] the updated +subject+
|
160
|
-
def put_in(subject, new_value)
|
161
|
-
_, new_data = self.get_and_update_in(subject){ [nil, new_value] }
|
162
|
-
new_data
|
163
|
-
end
|
164
|
-
|
165
|
-
# Traverses +subject+ using the chain of accessors held in this LensPath,
|
166
|
-
# removing the final value at the end of the traversal chain from its position
|
167
|
-
# within its parent container.
|
168
|
-
#
|
169
|
-
# *Equivalent* in Elixir: {https://hexdocs.pm/elixir/Kernel.html#pop_in/2 +Kernel.pop_in/2+}
|
170
|
-
#
|
171
|
-
# @param subject [Object] the data-structure to traverse
|
172
|
-
# @return [Object] the updated +subject+
|
173
|
-
def pop_in(subject)
|
174
|
-
self.get_and_update_in(subject){ :pop }
|
175
|
-
end
|
176
|
-
|
177
|
-
protected
|
178
|
-
def append_accessor!(part)
|
179
|
-
accessor =
|
180
|
-
case part
|
181
|
-
when Accessory::Accessor
|
182
|
-
part
|
183
|
-
when Array
|
184
|
-
Accessory::SubscriptAccessor.new(part[0], default: part[1])
|
185
|
-
else
|
186
|
-
Accessory::SubscriptAccessor.new(part)
|
187
|
-
end
|
188
|
-
|
189
|
-
unless @parts.empty?
|
190
|
-
@parts.last.succ_default_data_constructor = accessor.default_data_constructor
|
191
|
-
end
|
192
|
-
|
193
|
-
@parts.push(accessor)
|
194
|
-
end
|
195
|
-
|
196
|
-
private
|
197
|
-
def get_in_step(data, path)
|
198
|
-
step_accessor = path.first
|
199
|
-
rest_of_path = path[1..-1]
|
200
|
-
|
201
|
-
if rest_of_path.empty?
|
202
|
-
step_accessor.get(data)
|
203
|
-
else
|
204
|
-
step_accessor.get(data){ |v| get_in_step(v, rest_of_path) }
|
205
|
-
end
|
206
|
-
end
|
207
|
-
|
208
|
-
private
|
209
|
-
def get_and_update_in_step(data, path, mutator_fn)
|
210
|
-
step_accessor = path.first
|
211
|
-
rest_of_path = path[1..-1]
|
212
|
-
|
213
|
-
if rest_of_path.empty?
|
214
|
-
step_accessor.get_and_update(data, &mutator_fn)
|
215
|
-
else
|
216
|
-
step_accessor.get_and_update(data){ |v| get_and_update_in_step(v, rest_of_path, mutator_fn) }
|
217
|
-
end
|
218
|
-
end
|
219
|
-
end
|