accessory 0.1.6 → 0.1.11

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9880e7e5ea88c0b373a1cc3d5d4861788f368905c761b2ec3a7236d7282ada39
4
- data.tar.gz: 7386d98dc728a663904564e0a6825de0d7690e806950e5e95d6e8b39d4d20cd6
3
+ metadata.gz: 1a19c2c9d6ea2aeed4a4b0140c027220e383faa178d89689ebc667256fd9e228
4
+ data.tar.gz: 0c4ead2a9dd32de8b51c9c9da52aefafa16b05c272da5393b0e3d365dc920708
5
5
  SHA512:
6
- metadata.gz: dbee544b8dc699adb962559b98278d48edeed2a4d5b9c4d3c6c92ad3c4a38ffb4df5ced18274b465dfe68fd34dd15a50c06c2febae4e54049a4049d377cb10cd
7
- data.tar.gz: 0d1be0f43650e87a1616b5c2ac968b7407c5d8e380abb7e30ad84823816d486341a2c1b791814c55695dc77f2bf0337df834816c2a703bacbb2a3f582f362907
6
+ metadata.gz: fddd92947828fe5fd287ac183a5e7a3d0215da01314dd766737d7b8bf26c7e078a9207c1b1504e69522964e6e9a72b9b45372b10f35111a41c67bec4798da90d
7
+ data.tar.gz: 4ad13454e5adcd7b6243075c53e0b52539cbbc1402ab19d118ff065dfd25d5ac2fc5d3b052a3cec3055837bedae117fb4bddb226a3bbf66915a996c1344d47ef
data/lib/accessory.rb CHANGED
@@ -1,6 +1,3 @@
1
- ##
2
- #
3
-
4
1
  module Accessory; end
5
2
 
6
3
  require 'accessory/version'
@@ -18,59 +18,59 @@ require 'accessory/accessors/last_accessor'
18
18
  # include Accessory
19
19
 
20
20
  module Accessory::Access
21
- # (see Accessory::SubscriptAccessor)
21
+ # (see Accessory::Accessors::SubscriptAccessor)
22
22
  def self.subscript(...)
23
- Accessory::SubscriptAccessor.new(...)
23
+ Accessory::Accessors::SubscriptAccessor.new(...)
24
24
  end
25
25
 
26
- # (see Accessory::AttributeAccessor)
26
+ # (see Accessory::Accessors::AttributeAccessor)
27
27
  def self.attr(...)
28
- Accessory::AttributeAccessor.new(...)
28
+ Accessory::Accessors::AttributeAccessor.new(...)
29
29
  end
30
30
 
31
- # (see Accessory::InstanceVariableAccessor)
31
+ # (see Accessory::Accessors::InstanceVariableAccessor)
32
32
  def self.ivar(...)
33
- Accessory::InstanceVariableAccessor.new(...)
33
+ Accessory::Accessors::InstanceVariableAccessor.new(...)
34
34
  end
35
35
 
36
- # (see Accessory::BetwixtAccessor)
36
+ # (see Accessory::Accessors::BetwixtAccessor)
37
37
  def self.betwixt(...)
38
- Accessory::BetwixtAccessor.new(...)
38
+ Accessory::Accessors::BetwixtAccessor.new(...)
39
39
  end
40
40
 
41
- # Alias for +Accessory::Access.betwixt(0)+. See {Access.betwixt}
41
+ # Alias for +Accessory::Accessors::Access.betwixt(0)+. See {Access.betwixt}
42
42
  def self.before_first
43
43
  self.betwixt(0)
44
44
  end
45
45
 
46
- # Alias for +Accessory::Access.betwixt(-1)+. See {Access.betwixt}
46
+ # Alias for +Accessory::Accessors::Access.betwixt(-1)+. See {Access.betwixt}
47
47
  def self.after_last
48
48
  self.betwixt(-1)
49
49
  end
50
50
 
51
- # (see Accessory::BetweenEachAccessor)
51
+ # (see Accessory::Accessors::BetweenEachAccessor)
52
52
  def self.between_each
53
- Accessory::BetweenEachAccessor.new
53
+ Accessory::Accessors::BetweenEachAccessor.new
54
54
  end
55
55
 
56
- # (see Accessory::AllAccessor)
56
+ # (see Accessory::Accessors::AllAccessor)
57
57
  def self.all
58
- Accessory::AllAccessor.new
58
+ Accessory::Accessors::AllAccessor.new
59
59
  end
60
60
 
61
- # (see Accessory::FirstAccessor)
61
+ # (see Accessory::Accessors::FirstAccessor)
62
62
  def self.first
63
- Accessory::FirstAccessor.new
63
+ Accessory::Accessors::FirstAccessor.new
64
64
  end
65
65
 
66
- # (see Accessory::LastAccessor)
66
+ # (see Accessory::Accessors::LastAccessor)
67
67
  def self.last
68
- Accessory::LastAccessor.new
68
+ Accessory::Accessors::LastAccessor.new
69
69
  end
70
70
 
71
- # (see Accessory::FilterAccessor)
71
+ # (see Accessory::Accessors::FilterAccessor)
72
72
  def self.filter(&pred)
73
- Accessory::FilterAccessor.new(pred)
73
+ Accessory::Accessors::FilterAccessor.new(pred)
74
74
  end
75
75
  end
76
76
 
@@ -83,29 +83,29 @@ end
83
83
  # {Lens} or {BoundLens} from the addition of the accessor.
84
84
 
85
85
  module Accessory::Access::FluentHelpers
86
- # (see Accessory::SubscriptAccessor)
86
+ # (see Accessory::Accessors::SubscriptAccessor)
87
87
  def subscript(...)
88
- self.then(Accessory::SubscriptAccessor.new(...))
88
+ self.then(Accessory::Accessors::SubscriptAccessor.new(...))
89
89
  end
90
90
 
91
91
  # Alias for {#subscript}
92
92
  def [](...)
93
- self.then(Accessory::SubscriptAccessor.new(...))
93
+ self.then(Accessory::Accessors::SubscriptAccessor.new(...))
94
94
  end
95
95
 
96
- # (see Accessory::AttributeAccessor)
96
+ # (see Accessory::Accessors::AttributeAccessor)
97
97
  def attr(...)
98
- self.then(Accessory::AttributeAccessor.new(...))
98
+ self.then(Accessory::Accessors::AttributeAccessor.new(...))
99
99
  end
100
100
 
101
- # (see Accessory::InstanceVariableAccessor)
101
+ # (see Accessory::Accessors::InstanceVariableAccessor)
102
102
  def ivar(...)
103
- self.then(Accessory::InstanceVariableAccessor.new(...))
103
+ self.then(Accessory::Accessors::InstanceVariableAccessor.new(...))
104
104
  end
105
105
 
106
- # (see Accessory::BetwixtAccessor)
106
+ # (see Accessory::Accessors::BetwixtAccessor)
107
107
  def betwixt(...)
108
- self.then(Accessory::BetwixtAccessor.new(...))
108
+ self.then(Accessory::Accessors::BetwixtAccessor.new(...))
109
109
  end
110
110
 
111
111
  # Alias for +#betwixt(0)+. See {#betwixt}
@@ -118,29 +118,29 @@ module Accessory::Access::FluentHelpers
118
118
  self.betwixt(-1)
119
119
  end
120
120
 
121
- # (see Accessory::BetweenEachAccessor)
121
+ # (see Accessory::Accessors::BetweenEachAccessor)
122
122
  def between_each
123
- self.then(Accessory::BetweenEachAccessor.new)
123
+ self.then(Accessory::Accessors::BetweenEachAccessor.new)
124
124
  end
125
125
 
126
- # (see Accessory::AllAccessor)
126
+ # (see Accessory::Accessors::AllAccessor)
127
127
  def all
128
- self.then(Accessory::AllAccessor.new)
128
+ self.then(Accessory::Accessors::AllAccessor.new)
129
129
  end
130
130
 
131
- # (see Accessory::FirstAccessor)
131
+ # (see Accessory::Accessors::FirstAccessor)
132
132
  def first
133
- self.then(Accessory::FirstAccessor.new)
133
+ self.then(Accessory::Accessors::FirstAccessor.new)
134
134
  end
135
135
 
136
- # (see Accessory::LastAccessor)
136
+ # (see Accessory::Accessors::LastAccessor)
137
137
  def last
138
- self.then(Accessory::LastAccessor.new)
138
+ self.then(Accessory::Accessors::LastAccessor.new)
139
139
  end
140
140
 
141
- # (see Accessory::FilterAccessor)
141
+ # (see Accessory::Accessors::FilterAccessor)
142
142
  def filter(&pred)
143
- self.then(Accessory::FilterAccessor.new(pred))
143
+ self.then(Accessory::Accessors::FilterAccessor.new(pred))
144
144
  end
145
145
  end
146
146
 
@@ -19,7 +19,7 @@ module Accessory; end
19
19
  # info):
20
20
  #
21
21
  # * {Accessor#traverse}
22
- # * {Accessor#default_data_constructor}
22
+ # * {Accessor#ensure_valid}
23
23
 
24
24
  class Accessory::Accessor
25
25
  TERMINAL_DEFAULT_FN = lambda{ nil }
@@ -78,16 +78,13 @@ class Accessory::Accessor
78
78
  # call <tt>traverse_or_default(data)</tt> within your implementation to safely
79
79
  # get a traversal-result to operate on.
80
80
  #
81
- # This method will return +nil+ if the input-data is +nil+, _without_ calling
82
- # your {traverse} callback. This means that accessors that use
83
- # {traverse_or_default} will _forward_ +nil+ traversal-results along the chain
84
- # without being confused by them.
85
- #
86
- # If your {traverse} callback returns <tt>:error</tt>, a default value will
87
- # be used. This is either the +default+ passed to {initialize} by your
88
- # implementation calling <tt>super(default)</tt>; or it's the result of
89
- # calling {default_data_constructor} on the successor-accessor in the accessor
90
- # chain.
81
+ # The value returned by your {traverse} callback will be validated by your
82
+ # calling the {ensure_valid} callback of the _successor accessor_ in the Lens
83
+ # path. {ensure_valid} will replace any value it considers invalid with a
84
+ # reasonable default. This means you don't need to worry about what will
85
+ # happen if your traversal doesn't find a value and so returns +nil+. The
86
+ # successor's {ensure_valid} will replace that +nil+ with a value that works
87
+ # for it.
91
88
  def traverse_or_default(data)
92
89
  traversal_result = traverse(data) || @default_value
93
90
 
@@ -137,7 +134,8 @@ class Accessory::Accessor
137
134
  # of the +get_result+s should replicate the data flow of {get}.
138
135
  # * the +new_value+ should be used to *replace* or *overwrite* the result of
139
136
  # this accessor's traversal within +data+. For example, in
140
- # {SubscriptAccessor}, <tt>data[key] = new_value</tt> is executed.
137
+ # {Accessors::SubscriptAccessor}, <tt>data[key] = new_value</tt> is
138
+ # executed.
141
139
  #
142
140
  # In the <tt>:pop</tt> command case:
143
141
  # * the result of the traversal (*before* the yield) should be returned. This
@@ -145,7 +143,7 @@ class Accessory::Accessor
145
143
  # traversal-results before feeding them into yield, in order to return them
146
144
  # here.
147
145
  # * the traversal-result should be *removed* from +data+. For example, in
148
- # {SubscriptAccessor}, <tt>data.delete(key)</tt> is executed.
146
+ # {Accessors::SubscriptAccessor}, <tt>data.delete(key)</tt> is executed.
149
147
  #
150
148
  # The successor in the accessor chain will receive the yielded
151
149
  # traversal-results as its own +data+.
@@ -198,9 +196,9 @@ class Accessory::Accessor
198
196
  #
199
197
  #
200
198
  # For example, if your accessor operates on +Enumerable+ values (like
201
- # {AllAccessor}), then this method should validate that the +traversal_result+
202
- # is +Enumerable+; and, if it isn't, return something that is — e.g. an empty
203
- # +Array+.
199
+ # {Accessors::AllAccessor}), then this method should validate that the
200
+ # +traversal_result+ is +Enumerable+; and, if it isn't, return something that
201
+ # is — e.g. an empty +Array+.
204
202
  #
205
203
  # This logic is used to replace invalid intermediate values (e.g. `nil`s and
206
204
  # scalars) with containers during {Lens#put_in} et al.
@@ -214,3 +212,5 @@ class Accessory::Accessor
214
212
 
215
213
  # @!endgroup
216
214
  end
215
+
216
+ module Accessory::Accessors; end
@@ -15,7 +15,7 @@ require 'accessory/accessor'
15
15
  #
16
16
  # * +Array.new+
17
17
 
18
- class Accessory::AllAccessor < Accessory::Accessor
18
+ class Accessory::Accessors::AllAccessor < Accessory::Accessor
19
19
  # @!visibility private
20
20
  def ensure_valid(traversal_result)
21
21
  if traversal_result.kind_of?(Enumerable)
@@ -50,17 +50,28 @@ class Accessory::AllAccessor < Accessory::Accessor
50
50
  def get_and_update(data)
51
51
  results = []
52
52
  new_data = []
53
+ dirty = false
53
54
 
54
55
  (data || []).each do |pos|
55
56
  case yield(pos)
56
- in [result, new_value]
57
+ in [:clean, result, _]
58
+ results.push(result)
59
+ new_data.push(pos)
60
+ # ok
61
+ in [:dirty, result, new_value]
57
62
  results.push(result)
58
63
  new_data.push(new_value)
64
+ dirty = true
59
65
  in :pop
60
66
  results.push(pos)
67
+ dirty = true
61
68
  end
62
69
  end
63
70
 
64
- [results, new_data]
71
+ if dirty
72
+ [:dirty, results, new_data]
73
+ else
74
+ [:clean, results, data]
75
+ end
65
76
  end
66
77
  end
@@ -8,8 +8,8 @@ require 'accessory/accessor'
8
8
  # the getter/setter pair <tt>.foo</tt> and <tt>.foo=</tt>.
9
9
  #
10
10
  # The abstract "attribute" does not have to correspond to an actual
11
- # +attr_accessor+; the {AttributeAccessor} will work as long as the relevant
12
- # named getter/setter methods exist on the receiver.
11
+ # +attr_accessor+; the AttributeAccessor will work as long as the
12
+ # relevant named getter/setter methods exist on the receiver.
13
13
  #
14
14
  # *Aliases*
15
15
  # * {Access.attr}
@@ -19,7 +19,7 @@ require 'accessory/accessor'
19
19
  #
20
20
  # * +OpenStruct.new+
21
21
 
22
- class Accessory::AttributeAccessor < Accessory::Accessor
22
+ class Accessory::Accessors::AttributeAccessor < Accessory::Accessor
23
23
  # @param attr_name [Symbol] the attribute name (i.e. name of the getter method)
24
24
  # @param default [Object] the default to use if the predecessor accessor passes +nil+ data
25
25
  def initialize(attr_name, default: nil)
@@ -88,12 +88,14 @@ class Accessory::AttributeAccessor < Accessory::Accessor
88
88
  value = traverse_or_default(data)
89
89
 
90
90
  case yield(value)
91
- in [result, new_value]
91
+ in [:clean, result, _]
92
+ [:clean, result, data]
93
+ in [:dirty, result, new_value]
92
94
  data.send(@setter_method_name, new_value)
93
- [result, data]
95
+ [:dirty, result, data]
94
96
  in :pop
95
97
  data.send(@setter_method_name, nil)
96
- [value, data]
98
+ [:dirty, value, data]
97
99
  end
98
100
  end
99
101
  end
@@ -5,7 +5,7 @@ require 'accessory/traversal_position/enumerable_before_offset'
5
5
  # Traverses the positions "between" the elements of an +Enumerable+, including
6
6
  # the positions at the "edges" (i.e. before the first, and after the last.)
7
7
  #
8
- # {BetweenEachAccessor} can be used with {Lens#put_in} to insert new
8
+ # BetweenEachAccessor can be used with {Lens#put_in} to insert new
9
9
  # elements into an Enumerable between the existing ones.
10
10
  #
11
11
  # *Aliases*
@@ -16,7 +16,7 @@ require 'accessory/traversal_position/enumerable_before_offset'
16
16
  #
17
17
  # * +Array.new+
18
18
 
19
- class Accessory::BetweenEachAccessor < Accessory::Accessor
19
+ class Accessory::Accessors::BetweenEachAccessor < Accessory::Accessor
20
20
  # @!visibility private
21
21
  def ensure_valid(traversal_result)
22
22
  if traversal_result.kind_of?(Enumerable)
@@ -75,15 +75,20 @@ class Accessory::BetweenEachAccessor < Accessory::Accessor
75
75
  def get_and_update(data)
76
76
  results = []
77
77
  new_data = []
78
+ dirty = false
78
79
 
79
80
  positions = traverse_or_default(data || [])
80
81
 
81
82
  positions.each do |pos|
82
83
  case yield(pos)
83
- in [result, new_value]
84
+ in [:clean, result, _]
85
+ results.push(result)
86
+ in [:dirty, result, new_value]
84
87
  new_data.push(new_value)
85
88
  results.push(result)
89
+ dirty = true
86
90
  in :pop
91
+ # ok
87
92
  end
88
93
 
89
94
  unless pos.last?
@@ -91,6 +96,10 @@ class Accessory::BetweenEachAccessor < Accessory::Accessor
91
96
  end
92
97
  end
93
98
 
94
- [results, new_data]
99
+ if dirty
100
+ [:dirty, results, new_data]
101
+ else
102
+ [:clean, results, data]
103
+ end
95
104
  end
96
105
  end
@@ -13,10 +13,11 @@ require 'accessory/traversal_position/enumerable_before_offset'
13
13
  # The +offset+ in this accessor has equivalent semantics to the offset in
14
14
  # <tt>Array#insert(offset, obj)</tt>.
15
15
  #
16
- # {BetwixtAccessor} can be used with {Lens#put_in} to insert new
16
+ # {Accessors::BetwixtAccessor} can be used with {Lens#put_in} to insert new
17
17
  # elements into an Enumerable between the existing ones. If you want to extend
18
18
  # an +Enumerable+ as you would with <tt>#push</tt> or <tt>#unshift</tt>, this
19
- # accessor will have better behavior than using {SubscriptAccessor} would.
19
+ # accessor will have better behavior than using {Accessors::SubscriptAccessor}
20
+ # would.
20
21
  #
21
22
  # *Aliases*
22
23
  # * {Access.betwixt}
@@ -26,7 +27,7 @@ require 'accessory/traversal_position/enumerable_before_offset'
26
27
  #
27
28
  # * +Array.new+
28
29
 
29
- class Accessory::BetwixtAccessor < Accessory::Accessor
30
+ class Accessory::Accessors::BetwixtAccessor < Accessory::Accessor
30
31
  # @param offset [Integer] the cursor position (i.e. the index of the element after the cursor)
31
32
  # @param default [Object] the default to use if the predecessor accessor passes +nil+ data
32
33
  def initialize(offset, default: nil)
@@ -99,12 +100,14 @@ class Accessory::BetwixtAccessor < Accessory::Accessor
99
100
  pos = traverse_or_default(data || [])
100
101
 
101
102
  case yield(pos)
102
- in [result, new_value]
103
+ in [:dirty, result, new_value]
103
104
  data ||= []
104
105
  data.insert(@offset, new_value)
105
- [result, data]
106
+ [:dirty, result, data]
106
107
  in :pop
107
- [nil, data]
108
+ [:clean, nil, data]
109
+ in [:clean, result, _]
110
+ [:clean, result, data]
108
111
  end
109
112
  end
110
113
  end
@@ -15,7 +15,7 @@ require 'accessory/accessor'
15
15
  #
16
16
  # * +Array.new+
17
17
 
18
- class Accessory::FilterAccessor < Accessory::Accessor
18
+ class Accessory::Accessors::FilterAccessor < Accessory::Accessor
19
19
  # Returns a new instance of {FilterAccessor}.
20
20
  #
21
21
  # The predicate function may be passed in as either a positional argument,
@@ -65,6 +65,7 @@ class Accessory::FilterAccessor < Accessory::Accessor
65
65
  def get_and_update(data)
66
66
  results = []
67
67
  new_data = []
68
+ dirty = false
68
69
 
69
70
  (data || []).each do |pos|
70
71
  unless @pred.call(pos)
@@ -73,14 +74,23 @@ class Accessory::FilterAccessor < Accessory::Accessor
73
74
  end
74
75
 
75
76
  case yield(pos)
76
- in [result, new_value]
77
+ in [:clean, result, _]
78
+ results.push(result)
79
+ new_data.push(pos)
80
+ in [:dirty, result, new_value]
77
81
  results.push(result)
78
82
  new_data.push(new_value)
83
+ dirty = true
79
84
  in :pop
80
85
  results.push(pos)
86
+ dirty = true
81
87
  end
82
88
  end
83
89
 
84
- [results, new_data]
90
+ if dirty
91
+ [:dirty, results, new_data]
92
+ else
93
+ [:clean, results, data]
94
+ end
85
95
  end
86
96
  end
@@ -4,8 +4,8 @@ require 'accessory/accessor'
4
4
  # Traverses into the "first" element within an +Enumerable+, using
5
5
  # <tt>#first</tt>.
6
6
  #
7
- # This accessor can be preferable to {SubscriptAccessor} for objects that
8
- # are not subscriptable, e.g. {Range}.
7
+ # This accessor can be preferable to {Accessors::SubscriptAccessor} for objects
8
+ # that are not subscriptable, e.g. +Range+.
9
9
  #
10
10
  # *Aliases*
11
11
  # * {Access.first}
@@ -15,7 +15,7 @@ require 'accessory/accessor'
15
15
  #
16
16
  # * +Array.new+
17
17
 
18
- class Accessory::FirstAccessor < Accessory::Accessor
18
+ class Accessory::Accessors::FirstAccessor < Accessory::Accessor
19
19
  # @!visibility private
20
20
  def ensure_valid(traversal_result)
21
21
  if traversal_result.kind_of?(Enumerable)
@@ -58,16 +58,18 @@ class Accessory::FirstAccessor < Accessory::Accessor
58
58
  old_value = traverse_or_default(data)
59
59
 
60
60
  case yield(old_value)
61
- in [result, new_value]
61
+ in [:clean, result, _]
62
+ [:clean, result, data]
63
+ in [:dirty, result, new_value]
62
64
  if data.respond_to?(:"first=")
63
65
  data.first = new_value
64
66
  else
65
67
  data[0] = new_value
66
68
  end
67
- [result, data]
69
+ [:dirty, result, data]
68
70
  in :pop
69
71
  data.delete_at(0)
70
- [old_value, data]
72
+ [:dirty, old_value, data]
71
73
  end
72
74
  end
73
75
  end
@@ -14,7 +14,7 @@ require 'accessory/accessor'
14
14
  #
15
15
  # * +Object.new+
16
16
 
17
- class Accessory::InstanceVariableAccessor < Accessory::Accessor
17
+ class Accessory::Accessors::InstanceVariableAccessor < Accessory::Accessor
18
18
  # @param ivar_name [Symbol] the instance-variable name
19
19
  # @param default [Object] the default to use if the predecessor accessor passes +nil+ data
20
20
  def initialize(ivar_name, default: nil)
@@ -70,12 +70,14 @@ class Accessory::InstanceVariableAccessor < Accessory::Accessor
70
70
  value = traverse_or_default(data)
71
71
 
72
72
  case yield(value)
73
- in [result, new_value]
73
+ in [:clean, result, _]
74
+ [:clean, result, data]
75
+ in [:dirty, result, new_value]
74
76
  data.instance_variable_set(@ivar_name, new_value)
75
- [result, data]
77
+ [:dirty, result, data]
76
78
  in :pop
77
79
  data.remove_instance_variable(@ivar_name)
78
- [value, data]
80
+ [:dirty, value, data]
79
81
  end
80
82
  end
81
83
  end
@@ -4,8 +4,8 @@ require 'accessory/accessor'
4
4
  # Traverses into the "last" element within an +Enumerable+, using
5
5
  # <tt>#last</tt>.
6
6
  #
7
- # This accessor can be preferable to {SubscriptAccessor} for objects that
8
- # are not subscriptable, e.g. {Range}.
7
+ # This accessor can be preferable to {Accessors::SubscriptAccessor} for objects
8
+ # that are not subscriptable, e.g. +Range+.
9
9
  #
10
10
  # *Aliases*
11
11
  # * {Access.last}
@@ -15,7 +15,7 @@ require 'accessory/accessor'
15
15
  #
16
16
  # * +Array.new+
17
17
 
18
- class Accessory::LastAccessor < Accessory::Accessor
18
+ class Accessory::Accessors::LastAccessor < Accessory::Accessor
19
19
  # @!visibility private
20
20
  def ensure_valid(traversal_result)
21
21
  if traversal_result.kind_of?(Enumerable)
@@ -58,16 +58,18 @@ class Accessory::LastAccessor < Accessory::Accessor
58
58
  old_value = traverse_or_default(data)
59
59
 
60
60
  case yield(old_value)
61
- in [result, new_value]
61
+ in [:clean, result, _]
62
+ [:clean, result, data]
63
+ in [:dirty, result, new_value]
62
64
  if data.respond_to?(:"last=")
63
65
  data.last = new_value
64
66
  else
65
67
  data[-1] = new_value
66
68
  end
67
- [result, data]
69
+ [:dirty, result, data]
68
70
  in :pop
69
71
  data.delete_at(-1)
70
- [old_value, data]
72
+ [:dirty, old_value, data]
71
73
  end
72
74
  end
73
75
  end
@@ -29,9 +29,9 @@ require 'accessory/accessor'
29
29
  # # default-constructs a Hash, not an Array
30
30
  # [].lens[0][0].put_in(1) # => [{0=>1}]
31
31
  #
32
- # Other accessors ({FirstAccessor}, {BetwixtAccessor}, etc.) may fit your expectations more closely for +Array+ traversal.
32
+ # Other accessors ({Accessors::FirstAccessor}, {Accessors::BetwixtAccessor}, etc.) may fit your expectations more closely for +Array+ traversal.
33
33
 
34
- class Accessory::SubscriptAccessor < Accessory::Accessor
34
+ class Accessory::Accessors::SubscriptAccessor < Accessory::Accessor
35
35
  # @!visibility private
36
36
  def initialize(key, **kwargs)
37
37
  super(**kwargs)
@@ -92,12 +92,14 @@ class Accessory::SubscriptAccessor < Accessory::Accessor
92
92
  value = traverse_or_default(data)
93
93
 
94
94
  case yield(value)
95
- in [result, new_value]
95
+ in [:clean, result, _]
96
+ [:clean, result, data]
97
+ in [:dirty, result, new_value]
96
98
  data[@key] = new_value
97
- [result, data]
99
+ [:dirty, result, data]
98
100
  in :pop
99
101
  data.delete(@key)
100
- [value, data]
102
+ [:dirty, value, data]
101
103
  end
102
104
  end
103
105
  end
@@ -164,7 +164,17 @@ class Accessory::Lens
164
164
  # 1. the _old_ value(s) found after all traversals, and
165
165
  # 2. the updated +subject+
166
166
  def update_in(subject, &new_value_fn)
167
- _, new_data = self.get_and_update_in(data){ |v| [nil, new_value_fn.call(v)] }
167
+ _, _, new_data = self.get_and_update_in(subject) do |v|
168
+ case new_value_fn.call(v)
169
+ in [:set, new_value]
170
+ [:dirty, nil, new_value]
171
+ in :keep
172
+ [:clean, nil, v]
173
+ in :pop
174
+ :pop
175
+ end
176
+ end
177
+
168
178
  new_data
169
179
  end
170
180
 
@@ -178,7 +188,7 @@ class Accessory::Lens
178
188
  # @param new_value [Object] a replacement value at the traversal position.
179
189
  # @return [Object] the updated +subject+
180
190
  def put_in(subject, new_value)
181
- _, new_data = self.get_and_update_in(subject){ [nil, new_value] }
191
+ _, _, new_data = self.get_and_update_in(subject){ [:dirty, nil, new_value] }
182
192
  new_data
183
193
  end
184
194
 
@@ -191,7 +201,8 @@ class Accessory::Lens
191
201
  # @param subject [Object] the data-structure to traverse
192
202
  # @return [Object] the updated +subject+
193
203
  def pop_in(subject)
194
- self.get_and_update_in(subject){ :pop }
204
+ _, popped_item, new_data = self.get_and_update_in(subject){ :pop }
205
+ [popped_item, new_data]
195
206
  end
196
207
 
197
208
  def append_accessor!(part)
@@ -200,9 +211,9 @@ class Accessory::Lens
200
211
  when Accessory::Accessor
201
212
  part
202
213
  when Array
203
- Accessory::SubscriptAccessor.new(part[0], default: part[1])
214
+ Accessory::Accessors::SubscriptAccessor.new(part[0], default: part[1])
204
215
  else
205
- Accessory::SubscriptAccessor.new(part)
216
+ Accessory::Accessors::SubscriptAccessor.new(part)
206
217
  end
207
218
 
208
219
  unless @parts.empty?
@@ -1,3 +1,3 @@
1
1
  module Accessory
2
- VERSION = "0.1.6"
2
+ VERSION = "0.1.11"
3
3
  end
metadata CHANGED
@@ -1,16 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: accessory
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
4
+ version: 0.1.11
5
5
  platform: ruby
6
6
  authors:
7
7
  - Levi Aul
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-01-13 00:00:00.000000000 Z
11
+ date: 2021-02-03 00:00:00.000000000 Z
12
12
  dependencies: []
13
- description:
13
+ description:
14
14
  email:
15
15
  - levi@leviaul.com
16
16
  executables: []
@@ -40,7 +40,7 @@ licenses:
40
40
  metadata:
41
41
  homepage_uri: https://github.com/tsutsu/accessory
42
42
  source_code_uri: https://github.com/tsutsu/accessory
43
- post_install_message:
43
+ post_install_message:
44
44
  rdoc_options: []
45
45
  require_paths:
46
46
  - lib
@@ -48,15 +48,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
48
48
  requirements:
49
49
  - - ">="
50
50
  - !ruby/object:Gem::Version
51
- version: 2.7.0
51
+ version: 2.6.0
52
52
  required_rubygems_version: !ruby/object:Gem::Requirement
53
53
  requirements:
54
54
  - - ">="
55
55
  - !ruby/object:Gem::Version
56
56
  version: '0'
57
57
  requirements: []
58
- rubygems_version: 3.2.3
59
- signing_key:
58
+ rubygems_version: 3.0.3
59
+ signing_key:
60
60
  specification_version: 4
61
61
  summary: Functional lenses for Ruby, borrowed from Elixir
62
62
  test_files: []