ecoportal-api-v2 1.1.6 → 1.1.8
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/.rubocop.yml +54 -15
- data/CHANGELOG.md +17 -2
- data/lib/ecoportal/api/common/concerns/benchmarkable.rb +160 -0
- data/lib/ecoportal/api/common/concerns.rb +10 -0
- data/lib/ecoportal/api/common/content/array_model.rb +82 -79
- data/lib/ecoportal/api/common/content/class_helpers.rb +25 -26
- data/lib/ecoportal/api/common/content/collection_model.rb +108 -84
- data/lib/ecoportal/api/common/content/double_model.rb +125 -87
- data/lib/ecoportal/api/common.v2.rb +1 -0
- data/lib/ecoportal/api/v2/page/component.rb +60 -64
- data/lib/ecoportal/api/v2/page/components.rb +9 -9
- data/lib/ecoportal/api/v2/page/force.rb +5 -6
- data/lib/ecoportal/api/v2/page.rb +13 -14
- data/lib/ecoportal/api/v2_version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 70ba8da2cd5c6bd11498fb6cf8a40b04d121940c1693efc525372e3a584758f8
|
4
|
+
data.tar.gz: 2aa49af74223a5a03529fd3920714ff9b4f1dcbc636285c6b187acebe9b2e601
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 75a8af0bc9495b4ba65688914eaf2ac94e4b08756581a3e6f193c390376ae6d905d08321ba8c8017675e1d2991ce1c699176f74c4c7b4b3b7aa91edbd8b37325
|
7
|
+
data.tar.gz: ea3368515e1fb001874e4e932902e063bb2e1cbf015cb352c2813313bb97abd80c446e5f9ab623fa11dbc0dc8e9c164c5b1947475d7a43c935da91ac34c9be22
|
data/.rubocop.yml
CHANGED
@@ -1,39 +1,70 @@
|
|
1
1
|
AllCops:
|
2
|
-
TargetRubyVersion: 2.
|
2
|
+
TargetRubyVersion: 2.7.8
|
3
3
|
Exclude:
|
4
4
|
- 'config/routes.rb'
|
5
|
+
NewCops: enable
|
5
6
|
|
6
|
-
Metrics/
|
7
|
-
|
8
|
-
Metrics/
|
9
|
-
|
10
|
-
Max: 50
|
7
|
+
Metrics/ClassLength:
|
8
|
+
Max: 500
|
9
|
+
Metrics/ModuleLength:
|
10
|
+
Max: 300
|
11
11
|
Metrics/MethodLength:
|
12
12
|
Max: 50
|
13
|
-
Metrics/ClassLength:
|
14
|
-
Max: 200
|
15
13
|
Metrics/AbcSize:
|
16
14
|
Max: 30
|
17
|
-
|
18
|
-
ParameterLists:
|
15
|
+
Metrics/ParameterLists:
|
19
16
|
Max: 5
|
20
17
|
CountKeywordArgs: false
|
18
|
+
Metrics/BlockLength:
|
19
|
+
CountAsOne: ['array', 'heredoc', 'method_call']
|
20
|
+
Max: 50
|
21
|
+
Metrics/CyclomaticComplexity:
|
22
|
+
Max: 30
|
23
|
+
Metrics/PerceivedComplexity:
|
24
|
+
Max: 30
|
21
25
|
|
22
|
-
Style/
|
26
|
+
Style/AccessorGrouping:
|
27
|
+
Enabled: false
|
28
|
+
Style/ConditionalAssignment:
|
29
|
+
Enabled: false
|
30
|
+
Style/BlockDelimiters:
|
31
|
+
BracesRequiredMethods: ['log']
|
32
|
+
Style/ClassAndModuleChildren:
|
23
33
|
Enabled: false
|
24
34
|
Style/FrozenStringLiteralComment:
|
25
35
|
Enabled: false
|
26
|
-
Style/
|
36
|
+
Style/StringLiterals:
|
27
37
|
Enabled: false
|
28
|
-
Style/
|
38
|
+
Style/StringLiteralsInInterpolation:
|
29
39
|
Enabled: false
|
30
40
|
Style/Documentation:
|
31
41
|
Enabled: false
|
32
|
-
Style/
|
42
|
+
Style/CommentedKeyword:
|
43
|
+
Enabled: false
|
44
|
+
Style/MultilineBlockChain:
|
33
45
|
Enabled: false
|
34
46
|
Style/AndOr:
|
35
47
|
Enabled: false
|
48
|
+
Style/Alias:
|
49
|
+
EnforcedStyle: prefer_alias_method
|
50
|
+
Style/FetchEnvVar:
|
51
|
+
Enabled: false
|
52
|
+
Style/RegexpLiteral:
|
53
|
+
EnforcedStyle: mixed
|
54
|
+
AllowInnerSlashes: true
|
36
55
|
|
56
|
+
Layout/HashAlignment:
|
57
|
+
EnforcedColonStyle: table
|
58
|
+
EnforcedHashRocketStyle: table
|
59
|
+
Layout/LeadingCommentSpace:
|
60
|
+
Enabled: false
|
61
|
+
AllowGemfileRubyComment: true
|
62
|
+
Layout/ParameterAlignment:
|
63
|
+
Enabled: false
|
64
|
+
Layout/MultilineMethodDefinitionBraceLayout:
|
65
|
+
EnforcedStyle: symmetrical
|
66
|
+
Layout/LineLength:
|
67
|
+
Enabled: true
|
37
68
|
Layout/SpaceInsideHashLiteralBraces:
|
38
69
|
Enabled: false
|
39
70
|
Layout/SpaceInsideBlockBraces:
|
@@ -42,14 +73,22 @@ Layout/SpaceAroundOperators:
|
|
42
73
|
Enabled: false
|
43
74
|
Layout/ExtraSpacing:
|
44
75
|
AllowForAlignment: true
|
76
|
+
AllowBeforeTrailingComments: true
|
45
77
|
Layout/AccessModifierIndentation:
|
46
78
|
EnforcedStyle: indent
|
47
79
|
Layout/DotPosition:
|
48
80
|
EnforcedStyle: trailing
|
49
81
|
Layout/MultilineMethodCallIndentation:
|
50
82
|
EnforcedStyle: indented
|
51
|
-
Layout/
|
83
|
+
Layout/FirstHashElementIndentation:
|
84
|
+
Enabled: false
|
85
|
+
Layout/EmptyLineAfterGuardClause:
|
52
86
|
Enabled: false
|
53
87
|
|
54
88
|
Naming/VariableNumber:
|
55
89
|
EnforcedStyle: snake_case
|
90
|
+
CheckSymbols: false
|
91
|
+
Naming/MethodParameterName:
|
92
|
+
AllowedNames: ['x', 'y', 'i', 'j', 'id', 'io']
|
93
|
+
Naming/RescuedExceptionsVariableName:
|
94
|
+
Enabled: false
|
data/CHANGELOG.md
CHANGED
@@ -1,11 +1,26 @@
|
|
1
1
|
# Change Log
|
2
2
|
All notable changes to this project will be documented in this file.
|
3
3
|
|
4
|
-
## [1.1.
|
4
|
+
## [1.1.8] - 2024-03-23
|
5
5
|
|
6
|
-
### Added
|
7
6
|
### Changed
|
7
|
+
- A lot of code tidy up
|
8
|
+
|
9
|
+
### Fixed
|
10
|
+
- `Ecoportal::API::Common::Conent::CollectionModel`
|
11
|
+
- correct `item` `klass` resolution
|
12
|
+
|
13
|
+
## [1.1.7] - 2024-03-13
|
14
|
+
|
15
|
+
### Added
|
16
|
+
- `Ecoportal::API::Common::Concerns::Benchmarkable`
|
17
|
+
- `Ecoportal::API::Common::Conent::CollectionModel`
|
18
|
+
- added ability to define **default** value for `read_only`
|
19
|
+
|
8
20
|
### Fixed
|
21
|
+
- `Ecoportal::API::Common::Content::CollectionModel` tidied up item `klass` scoping
|
22
|
+
- **added** some benchmarking too
|
23
|
+
- memoize `@_items`
|
9
24
|
|
10
25
|
## [1.1.6] - 2024-02-29
|
11
26
|
|
@@ -0,0 +1,160 @@
|
|
1
|
+
module Ecoportal
|
2
|
+
module API
|
3
|
+
module Common
|
4
|
+
module Concerns
|
5
|
+
# @note While benchmarking with multi-thread gives correct results
|
6
|
+
# for top unique block, will calculate the real time of each individual
|
7
|
+
# thread, which is way higher than a single thread. However, as they
|
8
|
+
# run in parallel, the total time would be the valid reference.
|
9
|
+
module Benchmarkable
|
10
|
+
private
|
11
|
+
|
12
|
+
def benchmark_enabled?
|
13
|
+
@benchmark_enabled = true if @benchmark_enabled.nil?
|
14
|
+
@benchmark_enabled
|
15
|
+
end
|
16
|
+
|
17
|
+
def benchmarking(ref = nil, print: false)
|
18
|
+
return yield unless benchmark_enabled?
|
19
|
+
benchmark_mem(ref, print: false) do
|
20
|
+
benchmark_time(ref, print: false) do
|
21
|
+
yield
|
22
|
+
end
|
23
|
+
end.tap do
|
24
|
+
puts "\n#{bench_summary_ref(ref)}" if print
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def benchmark_mem(ref = nil, print: false)
|
29
|
+
return yield unless benchmark_enabled?
|
30
|
+
memory_before = memory_usage
|
31
|
+
yield.tap do
|
32
|
+
memory_after = memory_usage
|
33
|
+
mb_footprint = ((memory_after - memory_before) / 1024.0).round(2)
|
34
|
+
bench_add_mem(ref, mb_footprint)
|
35
|
+
puts bench_str_mem(mb, ref: ref, reffix: true) if print
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def benchmark_time(ref = nil, print: false)
|
40
|
+
return yield unless benchmark_enabled?
|
41
|
+
result = nil
|
42
|
+
time = benchmark.realtime do
|
43
|
+
result = yield
|
44
|
+
end.round(2)
|
45
|
+
result.tap do
|
46
|
+
bench_add_time(ref, time)
|
47
|
+
puts bench_str_time(time, ref: ref, reffix: true) if print
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def benchmark_summary(ref = nil)
|
52
|
+
return '' unless benchmark_enabled?
|
53
|
+
return bench_summary_ref(ref) unless ref == :all
|
54
|
+
|
55
|
+
bench.keys.each_with_object([]) do |ref, out|
|
56
|
+
out << bench_summary_ref(ref)
|
57
|
+
end.join("\n")
|
58
|
+
end
|
59
|
+
|
60
|
+
def bench_summary_ref(ref = nil)
|
61
|
+
ref_lines = bench_summary_ref_lines(ref)
|
62
|
+
"- #{ref}\n" + " • " + ref_lines.join("\n • ")
|
63
|
+
end
|
64
|
+
|
65
|
+
def bench_summary_ref_lines(ref = nil)
|
66
|
+
ref_bench = bench_get(ref)
|
67
|
+
[
|
68
|
+
bench_str_time(*ref_bench[:time].values_at(:avg, :cnt), ref: ref),
|
69
|
+
bench_str_mem(*ref_bench[:mem].values_at(:avg, :cnt), ref: ref)
|
70
|
+
]
|
71
|
+
end
|
72
|
+
|
73
|
+
def benchmark
|
74
|
+
require 'benchmark'
|
75
|
+
Benchmark
|
76
|
+
end
|
77
|
+
|
78
|
+
def bench
|
79
|
+
@bench ||= {}
|
80
|
+
end
|
81
|
+
|
82
|
+
def bench_add_mem(ref, mem)
|
83
|
+
bench_data_push(bench_get(ref)[:mem], mem)
|
84
|
+
end
|
85
|
+
|
86
|
+
def bench_add_time(ref, time)
|
87
|
+
bench_data_push(bench_get(ref)[:time], time)
|
88
|
+
end
|
89
|
+
|
90
|
+
def bench_get(ref)
|
91
|
+
bench[ref] ||= {
|
92
|
+
time: bench_data,
|
93
|
+
mem: bench_data
|
94
|
+
}
|
95
|
+
end
|
96
|
+
|
97
|
+
def bench_data
|
98
|
+
{
|
99
|
+
avg: nil,
|
100
|
+
cnt: 0
|
101
|
+
}
|
102
|
+
end
|
103
|
+
|
104
|
+
def bench_data_push(data, value)
|
105
|
+
total = value + ( (data[:avg] || 0) * data[:cnt])
|
106
|
+
data[:cnt] += 1
|
107
|
+
data[:avg] = (total / data[:cnt]).round(3)
|
108
|
+
data
|
109
|
+
end
|
110
|
+
|
111
|
+
def bench_str_mem(mem, count = nil, ref: nil, reffix: false)
|
112
|
+
ref = reffix ? ref : nil
|
113
|
+
msg = [ref, 'Memory'].compact.join(' -- ')
|
114
|
+
cnt = count ? " (cnt: #{count})" : ''
|
115
|
+
"#{msg}: #{mem} MB#{cnt}"
|
116
|
+
end
|
117
|
+
|
118
|
+
def active_support_duration?
|
119
|
+
return false unless Kernel.const_defined?(:ActiveSupport)
|
120
|
+
ActiveSupport.const_defined?(:Duration, false)
|
121
|
+
end
|
122
|
+
|
123
|
+
def bench_str_time(time, count = nil, ref: nil, reffix: false)
|
124
|
+
ref = reffix ? ref : nil
|
125
|
+
msg = [ref, 'Time'].compact.join(' -- ')
|
126
|
+
total = (time * count).round(2)
|
127
|
+
str_desc = ''
|
128
|
+
if active_support_duration? && total >= 60
|
129
|
+
duration = ActiveSupport::Duration.build(total.round)
|
130
|
+
str_desc = ": #{duration_to_s(duration)}"
|
131
|
+
end
|
132
|
+
cnt = count ? " (cnt: #{count}; sum: #{total} s#{str_desc})" : ''
|
133
|
+
"#{msg}: #{time} s#{cnt}"
|
134
|
+
end
|
135
|
+
|
136
|
+
def duration_to_s(value)
|
137
|
+
return "" unless active_support_duration?
|
138
|
+
return "" if value.nil?
|
139
|
+
|
140
|
+
raise ArgumentError, "Expecint ActiveSupport::Duration. Given: #{value.class}" unless value.is_a?(ActiveSupport::Duration)
|
141
|
+
parts = value.parts.map {|pair| pair.reverse.join(" ")}
|
142
|
+
return parts.first if parts.length == 1
|
143
|
+
[parts[..-2].join(", "), parts.last].join(" and ")
|
144
|
+
end
|
145
|
+
|
146
|
+
# @return [Integer] total memory used by this process in KB
|
147
|
+
def memory_usage
|
148
|
+
if Gem.win_platform?
|
149
|
+
wmem = `wmic process where processid=#{Process.pid} get WorkingSetSize | findstr "[0-9]"`
|
150
|
+
return 0 unless wmem
|
151
|
+
wmem.lines.first.chop.strip.to_i / 1024.0
|
152
|
+
else
|
153
|
+
`ps -o rss= -p #{Process.pid}`.to_i
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
@@ -7,13 +7,9 @@ module Ecoportal
|
|
7
7
|
# - Its purpose is to handle an Array of basic objects (i.e. `Date`, `String`, `Number`)
|
8
8
|
class ArrayModel < Content::DoubleModel
|
9
9
|
class TypeMismatchedComparison < StandardError
|
10
|
-
def initialize
|
11
|
-
if this
|
12
|
-
|
13
|
-
end
|
14
|
-
if that
|
15
|
-
msg += " To object where 'order_matters: #{that.order_matters?}' and 'uniq: #{that.uniq?}'."
|
16
|
-
end
|
10
|
+
def initialize(this: nil, that: msg = "Trying to compare objects with different behavior.")
|
11
|
+
msg += " From object with 'order_matters: #{this.order_matters?}' and 'uniq: #{this.uniq?}'." if this
|
12
|
+
msg += " To object where 'order_matters: #{that.order_matters?}' and 'uniq: #{that.uniq?}'." if that
|
17
13
|
super(msg)
|
18
14
|
end
|
19
15
|
end
|
@@ -27,23 +23,37 @@ module Ecoportal
|
|
27
23
|
# @param b [ArrayModel]
|
28
24
|
# @return [Boolean] `true` if both elements have same behaviour
|
29
25
|
def same_type?(a, b)
|
30
|
-
|
26
|
+
msg = "To use this comparison both objects should be `ArrayModel`"
|
27
|
+
raise msg unless a.is_a?(ArrayModel) && b.is_a?(ArrayModel)
|
31
28
|
(a.order_matters? == b.order_matters?) && (a.uniq? == b.uniq?)
|
32
29
|
end
|
33
30
|
end
|
34
31
|
|
35
32
|
inheritable_class_vars :order_matteres, :uniq
|
36
33
|
|
37
|
-
def initialize(doc = [], parent: self, key: nil, read_only:
|
34
|
+
def initialize(doc = [], parent: self, key: nil, read_only: self.class.read_only?)
|
38
35
|
super(doc, parent: parent, key: key, read_only: read_only)
|
39
36
|
end
|
40
37
|
|
41
|
-
def order_matters
|
42
|
-
|
38
|
+
def order_matters?
|
39
|
+
self.class.order_matters
|
40
|
+
end
|
41
|
+
|
42
|
+
def uniq?
|
43
|
+
self.class.uniq
|
44
|
+
end
|
45
|
+
|
46
|
+
def length
|
47
|
+
count
|
48
|
+
end
|
43
49
|
|
44
|
-
def
|
45
|
-
|
46
|
-
|
50
|
+
def empty?
|
51
|
+
count&.zero?
|
52
|
+
end
|
53
|
+
|
54
|
+
def present?
|
55
|
+
count&.positive?
|
56
|
+
end
|
47
57
|
|
48
58
|
def each(&block)
|
49
59
|
return to_enum(:each) unless block
|
@@ -66,10 +76,10 @@ module Ecoportal
|
|
66
76
|
_items.slice(0..-1)
|
67
77
|
end
|
68
78
|
|
69
|
-
# @param
|
79
|
+
# @param other [Object, Array<Object>, ArrayModel] the value(s) of the new object
|
70
80
|
# @return [ArrayModel] a new object with the current class
|
71
|
-
def new_from(
|
72
|
-
self.class.new(into_a(
|
81
|
+
def new_from(other)
|
82
|
+
self.class.new(into_a(other))
|
73
83
|
end
|
74
84
|
|
75
85
|
# @return [ArrayModel] a copy of the current object
|
@@ -93,28 +103,28 @@ module Ecoportal
|
|
93
103
|
# @param pos [Integer] the position of the element
|
94
104
|
# @param value [String, Date, Number] the element
|
95
105
|
# @return [Date, String, Number]
|
96
|
-
def []=(
|
106
|
+
def []=(pos, value)
|
97
107
|
_items[pos] = value
|
98
108
|
on_change
|
99
109
|
self[pos]
|
100
110
|
end
|
101
111
|
|
102
112
|
# Compares with an `Array` or another `ArrayModel`
|
103
|
-
# @param
|
104
|
-
def ==(
|
105
|
-
return true
|
106
|
-
return false unless (
|
107
|
-
|
113
|
+
# @param other [ArrayModel, Array]
|
114
|
+
def ==(other)
|
115
|
+
return true if equal?(other)
|
116
|
+
return false unless (other.class == self.class) || other.is_a?(Array)
|
117
|
+
|
118
|
+
case other
|
108
119
|
when Array
|
109
|
-
self == new_from(
|
120
|
+
self == new_from(other)
|
110
121
|
when ArrayModel
|
111
|
-
|
112
|
-
raise TypeMismatchedComparison.new(this: self, that: a) unless self.class.same_type?(self, a)
|
122
|
+
raise TypeMismatchedComparison.new(this: self, that: other) unless self.class.same_type?(self, other)
|
113
123
|
|
114
|
-
if
|
115
|
-
_items ==
|
124
|
+
if order_matters?
|
125
|
+
_items == other.to_a
|
116
126
|
else
|
117
|
-
(_items -
|
127
|
+
(_items - other.to_a).empty? && (other.to_a - _items).empty?
|
118
128
|
end
|
119
129
|
end
|
120
130
|
end
|
@@ -154,11 +164,10 @@ module Ecoportal
|
|
154
164
|
end
|
155
165
|
|
156
166
|
# Resets the `Array` by keeping its reference and adds the value(s)
|
157
|
-
# @param
|
158
|
-
|
159
|
-
def <(values)
|
167
|
+
# @param other [Object, Array<Object>, ArrayModel] the value(s) to be added
|
168
|
+
def <(other)
|
160
169
|
_items.clear
|
161
|
-
self <<
|
170
|
+
self << other
|
162
171
|
end
|
163
172
|
|
164
173
|
# Clears the `Array` keeping its reference
|
@@ -169,25 +178,25 @@ module Ecoportal
|
|
169
178
|
end
|
170
179
|
|
171
180
|
# Concat to new
|
172
|
-
def +(
|
173
|
-
new_from(
|
181
|
+
def +(other)
|
182
|
+
new_from(to_a + into_a(other))
|
174
183
|
end
|
175
184
|
|
176
185
|
# Join
|
177
|
-
# @param
|
186
|
+
# @param other [Object, Array<Object>, ArrayModel] the value(s) to be joined
|
178
187
|
# @return [ArrayModel] a new object instance with the intersection done
|
179
|
-
def |(
|
180
|
-
|
181
|
-
new_from(to_a +
|
188
|
+
def |(other)
|
189
|
+
oth = new_from(other) - self
|
190
|
+
new_from(to_a + oth.to_a)
|
182
191
|
end
|
183
192
|
|
184
193
|
# Intersect
|
185
|
-
# @param
|
194
|
+
# @param other [Object, Array<Object>, ArrayModel] the value(s) to be deleted
|
186
195
|
# @return [ArrayModel] a new object instance with the intersection done
|
187
|
-
def &(
|
188
|
-
|
189
|
-
|
190
|
-
delta.delete!(*into_a(
|
196
|
+
def &(other)
|
197
|
+
dup.tap do |out|
|
198
|
+
dup.tap do |delta|
|
199
|
+
delta.delete!(*into_a(other))
|
191
200
|
out.delete!(*into_a(delta))
|
192
201
|
end
|
193
202
|
end
|
@@ -196,9 +205,9 @@ module Ecoportal
|
|
196
205
|
# Subtract
|
197
206
|
# @param value [Object, Array<Object>, ArrayModel] the value(s) to be deleted
|
198
207
|
# @return [ArrayModel] a **copy** of the object with the elements subtracted
|
199
|
-
def -(
|
200
|
-
|
201
|
-
copy.delete!(*into_a(
|
208
|
+
def -(other)
|
209
|
+
dup.tap do |copy|
|
210
|
+
copy.delete!(*into_a(other))
|
202
211
|
end
|
203
212
|
end
|
204
213
|
|
@@ -206,7 +215,7 @@ module Ecoportal
|
|
206
215
|
def delete!(*values)
|
207
216
|
values.map do |v|
|
208
217
|
deletion!(v)
|
209
|
-
end.tap do |
|
218
|
+
end.tap do |_r|
|
210
219
|
on_change
|
211
220
|
end
|
212
221
|
end
|
@@ -216,43 +225,41 @@ module Ecoportal
|
|
216
225
|
# @param val1 [Object] the first value to swap
|
217
226
|
# @param val2 [Object] the second value to swap
|
218
227
|
# @return [Integer] the new of `value1`, `nil` if it wasn't moved
|
219
|
-
def swap(
|
220
|
-
index(
|
221
|
-
if dest && pos = index(
|
222
|
-
_items[dest] =
|
223
|
-
_items[pos] =
|
228
|
+
def swap(val_1, val_2)
|
229
|
+
index(val_2).tap do |dest|
|
230
|
+
if dest && (pos = index(val_1))
|
231
|
+
_items[dest] = val_1
|
232
|
+
_items[pos] = val_2
|
224
233
|
end
|
225
234
|
end
|
226
235
|
end
|
227
236
|
|
228
237
|
def insert_one(value, pos: NOT_USED, before: NOT_USED, after: NOT_USED)
|
229
|
-
|
230
|
-
return
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
238
|
+
idx = index(value)
|
239
|
+
return idx if idx && uniq?
|
240
|
+
|
241
|
+
pos =
|
242
|
+
if used_param?(pos) && pos
|
243
|
+
pos
|
244
|
+
elsif used_param?(before) && before
|
245
|
+
index(before)
|
246
|
+
elsif used_param?(after) && after
|
247
|
+
if (idx = index(after)) then idx + 1 end
|
248
|
+
end
|
239
249
|
|
250
|
+
# use last position as default
|
240
251
|
pos ||= length
|
241
|
-
pos.tap do |
|
252
|
+
pos.tap do |_i|
|
242
253
|
_items.insert(pos, value)
|
243
254
|
on_change
|
244
255
|
end
|
245
256
|
end
|
246
257
|
|
247
258
|
# TODO
|
248
|
-
def move(value, pos: NOT_USED,
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
on_change
|
253
|
-
end
|
254
|
-
pos
|
255
|
-
end
|
259
|
+
def move(value, pos: NOT_USED, _before: NOT_USED, _after: NOT_USED)
|
260
|
+
return unless (idx = index(value))
|
261
|
+
on_change unless idx == pos
|
262
|
+
pos
|
256
263
|
end
|
257
264
|
|
258
265
|
protected
|
@@ -270,13 +277,9 @@ module Ecoportal
|
|
270
277
|
end
|
271
278
|
|
272
279
|
def deletion!(value)
|
273
|
-
if
|
274
|
-
|
275
|
-
|
276
|
-
end
|
277
|
-
else
|
278
|
-
_items.delete(value)
|
279
|
-
end
|
280
|
+
return _items.delete(value) if uniq?
|
281
|
+
return unless (idx = _items.index(value))
|
282
|
+
_items.slice!(idx)
|
280
283
|
end
|
281
284
|
end
|
282
285
|
end
|