ecoportal-api-v2 1.1.6 → 1.1.8
Sign up to get free protection for your applications and to get access to all the features.
- 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
|