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.
@@ -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 {LensPath#put_in} at this position
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 {LensPath#put_in} at this position
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 {LensPath#put_in} with an +EnumerableBeforeOffset+ with an
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 {LensPath#get_and_update_in} for an
27
- # +EnumerableBeforeOffset+-terminated {LensPath} will have no effect, as
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
@@ -1,3 +1,3 @@
1
1
  module Accessory
2
- VERSION = "0.1.5"
2
+ VERSION = "0.1.6"
3
3
  end
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.5
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-12 00:00:00.000000000 Z
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
@@ -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