accessory 0.1.2 → 0.1.7
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 +3 -3
- data/lib/accessory/access.rb +67 -21
- data/lib/accessory/accessor.rb +173 -13
- data/lib/accessory/accessors/all_accessor.rb +35 -3
- data/lib/accessory/accessors/attribute_accessor.rb +60 -8
- data/lib/accessory/accessors/between_each_accessor.rb +48 -8
- data/lib/accessory/accessors/betwixt_accessor.rb +75 -17
- data/lib/accessory/accessors/filter_accessor.rb +46 -5
- data/lib/accessory/accessors/first_accessor.rb +44 -7
- data/lib/accessory/accessors/instance_variable_accessor.rb +41 -8
- data/lib/accessory/accessors/last_accessor.rb +44 -7
- data/lib/accessory/accessors/subscript_accessor.rb +57 -6
- data/lib/accessory/bound_lens.rb +139 -0
- data/lib/accessory/lens.rb +197 -26
- data/lib/accessory/traversal_position/enumerable_at_offset.rb +28 -0
- data/lib/accessory/traversal_position/enumerable_before_offset.rb +55 -0
- data/lib/accessory/version.rb +1 -1
- metadata +5 -4
- data/lib/accessory/array_cursor_position.rb +0 -18
- data/lib/accessory/lens_path.rb +0 -150
@@ -0,0 +1,28 @@
|
|
1
|
+
module Accessory; end
|
2
|
+
module Accessory::TraversalPosition; end
|
3
|
+
|
4
|
+
##
|
5
|
+
# Represents an element encountered during +#each+ traversal of an +Enumerable+.
|
6
|
+
|
7
|
+
class Accessory::TraversalPosition::EnumerableAtOffset
|
8
|
+
##
|
9
|
+
# @!visibility private
|
10
|
+
def initialize(offset, elem_at, is_first: false, is_last: false)
|
11
|
+
@offset = offset
|
12
|
+
@elem_at = elem_at
|
13
|
+
@is_first = is_first
|
14
|
+
@is_last = is_last
|
15
|
+
end
|
16
|
+
|
17
|
+
# @return [Integer] the offset of +elem_at+ in the Enumerable
|
18
|
+
attr_reader :offset
|
19
|
+
|
20
|
+
# @return [Object] the element under the cursor, if applicable
|
21
|
+
attr_reader :elem_at
|
22
|
+
|
23
|
+
# @return [Boolean] true when {#elem_at} is the first element of the +Enumerable+
|
24
|
+
def first?; @is_first; end
|
25
|
+
|
26
|
+
# @return [Boolean] true when {#elem_at} is the last element of the +Enumerable+
|
27
|
+
def last?; @is_last; end
|
28
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Accessory; end
|
2
|
+
module Accessory::TraversalPosition; end
|
3
|
+
|
4
|
+
##
|
5
|
+
# Represents the empty intervals between and surrounding the elements of an
|
6
|
+
# +Enumerable#each+ traversal.
|
7
|
+
#
|
8
|
+
# Examples to build intuition:
|
9
|
+
#
|
10
|
+
# * An +EnumerableBeforeOffset+ with an <tt>.offset</tt> of <tt>0</tt>
|
11
|
+
# represents the position directly before the first result from
|
12
|
+
# <tt>#each</tt>, i.e. "the beginning." Using {Lens#put_in} at this position
|
13
|
+
# will _prepend_ to the +Enumerable+.
|
14
|
+
#
|
15
|
+
# * An +EnumerableBeforeOffset+ with an <tt>.offset</tt> equal to the
|
16
|
+
# <tt>#length</tt> of the +Enumerable+ (recognizable by
|
17
|
+
# <tt>EnumerableBeforeOffset#last?</tt> returning +true+) represents
|
18
|
+
# represents the position directly before the end of the enumeration,
|
19
|
+
# i.e. "the end" of the +Enumerable+. Using {Lens#put_in} at this position
|
20
|
+
# will _append_ to the +Enumerable+.
|
21
|
+
#
|
22
|
+
# * In general, using {Lens#put_in} with an +EnumerableBeforeOffset+ with an
|
23
|
+
# <tt>.offset</tt> of +n+ will insert an element _between_ elements
|
24
|
+
# <tt>n - 1</tt> and +n+ in the enumeration sequence.
|
25
|
+
#
|
26
|
+
# * Returning <tt>:pop</tt> from {Lens#get_and_update_in} for an
|
27
|
+
# +EnumerableBeforeOffset+-terminated {Lens} will have no effect, as
|
28
|
+
# you're removing an empty slice.
|
29
|
+
|
30
|
+
class Accessory::TraversalPosition::EnumerableBeforeOffset
|
31
|
+
##
|
32
|
+
# @!visibility private
|
33
|
+
def initialize(offset, elem_before, elem_after, is_first: false, is_last: false)
|
34
|
+
@offset = offset
|
35
|
+
@elem_before = elem_before
|
36
|
+
@elem_after = elem_after
|
37
|
+
@is_first = is_first
|
38
|
+
@is_last = is_last
|
39
|
+
end
|
40
|
+
|
41
|
+
# @return [Integer] the offset of +elem_after+ in the Enumerable
|
42
|
+
attr_reader :offset
|
43
|
+
|
44
|
+
# @return [Object] the element before the cursor, if applicable
|
45
|
+
attr_reader :elem_before
|
46
|
+
|
47
|
+
# @return [Object] the element after the cursor, if applicable
|
48
|
+
attr_reader :elem_after
|
49
|
+
|
50
|
+
# @return [Boolean] true when {#elem_after} is the first element of the +Enumerable+
|
51
|
+
def first?; @is_first; end
|
52
|
+
|
53
|
+
# @return [Boolean] true when {#elem_before} is the last element of the +Enumerable+
|
54
|
+
def last?; @is_last; end
|
55
|
+
end
|
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.7
|
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,9 +29,10 @@ 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/
|
32
|
+
- lib/accessory/bound_lens.rb
|
33
33
|
- lib/accessory/lens.rb
|
34
|
-
- lib/accessory/
|
34
|
+
- lib/accessory/traversal_position/enumerable_at_offset.rb
|
35
|
+
- lib/accessory/traversal_position/enumerable_before_offset.rb
|
35
36
|
- lib/accessory/version.rb
|
36
37
|
homepage: https://github.com/tsutsu/accessory
|
37
38
|
licenses:
|
@@ -1,18 +0,0 @@
|
|
1
|
-
module Accessory; end
|
2
|
-
|
3
|
-
class Accessory::ArrayCursorPosition
|
4
|
-
def initialize(offset, elem_before, elem_after, is_first: false, is_last: false)
|
5
|
-
@offset = offset
|
6
|
-
@elem_before = elem_before
|
7
|
-
@elem_after = elem_after
|
8
|
-
@is_first = is_first
|
9
|
-
@is_last = is_last
|
10
|
-
end
|
11
|
-
|
12
|
-
attr_reader :offset
|
13
|
-
attr_reader :elem_before
|
14
|
-
attr_reader :elem_after
|
15
|
-
|
16
|
-
def first?; @is_first; end
|
17
|
-
def last?; @is_last; end
|
18
|
-
end
|
data/lib/accessory/lens_path.rb
DELETED
@@ -1,150 +0,0 @@
|
|
1
|
-
module Accessory; end
|
2
|
-
|
3
|
-
require 'accessory/accessor'
|
4
|
-
require 'accessory/accessors/subscript_accessor'
|
5
|
-
|
6
|
-
class Accessory::LensPath
|
7
|
-
def self.empty
|
8
|
-
@empty_lens_path ||= (new([]).freeze)
|
9
|
-
end
|
10
|
-
|
11
|
-
def self.[](*path)
|
12
|
-
new(path).freeze
|
13
|
-
end
|
14
|
-
|
15
|
-
class << self
|
16
|
-
private :new
|
17
|
-
end
|
18
|
-
|
19
|
-
def initialize(initial_parts)
|
20
|
-
@parts = []
|
21
|
-
|
22
|
-
for part in initial_parts
|
23
|
-
append_accessor!(part)
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
def to_a
|
28
|
-
@parts
|
29
|
-
end
|
30
|
-
|
31
|
-
def inspect(format: :long)
|
32
|
-
parts_desc = @parts.map{ |part| part.inspect(format: :short) }.join(', ')
|
33
|
-
parts_desc = "[#{parts_desc}]"
|
34
|
-
|
35
|
-
case format
|
36
|
-
when :long
|
37
|
-
"#LensPath#{parts_desc}"
|
38
|
-
when :short
|
39
|
-
parts_desc
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
def then(accessor)
|
44
|
-
d = self.dup
|
45
|
-
d.append_accessor!(accessor)
|
46
|
-
d.freeze
|
47
|
-
end
|
48
|
-
|
49
|
-
def dup
|
50
|
-
d = super
|
51
|
-
d.instance_eval do
|
52
|
-
@parts = @parts.dup
|
53
|
-
end
|
54
|
-
d
|
55
|
-
end
|
56
|
-
|
57
|
-
def +(lp_b)
|
58
|
-
parts =
|
59
|
-
case lp_b
|
60
|
-
when Accessory::LensPath
|
61
|
-
lp_b.to_a
|
62
|
-
when Array
|
63
|
-
lp_b
|
64
|
-
else
|
65
|
-
[lp_b]
|
66
|
-
end
|
67
|
-
|
68
|
-
d = self.dup
|
69
|
-
for part in parts
|
70
|
-
d.append_accessor!(part)
|
71
|
-
end
|
72
|
-
d.freeze
|
73
|
-
end
|
74
|
-
|
75
|
-
alias_method :/, :+
|
76
|
-
|
77
|
-
def append_accessor!(part)
|
78
|
-
accessor =
|
79
|
-
case part
|
80
|
-
when Accessory::Accessor
|
81
|
-
part
|
82
|
-
when Array
|
83
|
-
Accessory::SubscriptAccessor.new(part[0], default: part[1])
|
84
|
-
else
|
85
|
-
Accessory::SubscriptAccessor.new(part)
|
86
|
-
end
|
87
|
-
|
88
|
-
unless @parts.empty?
|
89
|
-
@parts.last.make_default_fn = accessor.default_fn_for_previous_step
|
90
|
-
end
|
91
|
-
|
92
|
-
@parts.push(accessor)
|
93
|
-
end
|
94
|
-
|
95
|
-
protected :append_accessor!
|
96
|
-
|
97
|
-
def get_in(doc)
|
98
|
-
if @parts.empty?
|
99
|
-
doc
|
100
|
-
else
|
101
|
-
get_in_step(doc, @parts)
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
def get_and_update_in(doc, &mutator_fn)
|
106
|
-
if @parts.empty?
|
107
|
-
doc
|
108
|
-
else
|
109
|
-
get_and_update_in_step(doc, @parts, mutator_fn)
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
def update_in(data, &new_value_fn)
|
114
|
-
_, new_data = self.get_and_update_in(data){ |v| [nil, new_value_fn.call(v)] }
|
115
|
-
new_data
|
116
|
-
end
|
117
|
-
|
118
|
-
def put_in(data, new_value)
|
119
|
-
_, new_data = self.get_and_update_in(data){ [nil, new_value] }
|
120
|
-
new_data
|
121
|
-
end
|
122
|
-
|
123
|
-
def pop_in(data)
|
124
|
-
self.get_and_update_in(data){ :pop }
|
125
|
-
end
|
126
|
-
|
127
|
-
private
|
128
|
-
def get_in_step(data, path)
|
129
|
-
step_accessor = path.first
|
130
|
-
rest_of_path = path[1..-1]
|
131
|
-
|
132
|
-
if rest_of_path.empty?
|
133
|
-
step_accessor.get(data)
|
134
|
-
else
|
135
|
-
step_accessor.get(data){ |v| get_in_step(v, rest_of_path) }
|
136
|
-
end
|
137
|
-
end
|
138
|
-
|
139
|
-
private
|
140
|
-
def get_and_update_in_step(data, path, mutator_fn)
|
141
|
-
step_accessor = path.first
|
142
|
-
rest_of_path = path[1..-1]
|
143
|
-
|
144
|
-
if rest_of_path.empty?
|
145
|
-
step_accessor.get_and_update(data, &mutator_fn)
|
146
|
-
else
|
147
|
-
step_accessor.get_and_update(data){ |v| get_and_update_in_step(v, rest_of_path, mutator_fn) }
|
148
|
-
end
|
149
|
-
end
|
150
|
-
end
|