ecoportal-api-v2 0.8.4
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 +7 -0
- data/.gitignore +20 -0
- data/.rspec +3 -0
- data/.rubocop.yml +55 -0
- data/.travis.yml +5 -0
- data/.yardopts +10 -0
- data/CHANGELOG.md +171 -0
- data/Gemfile +6 -0
- data/LICENSE +21 -0
- data/README.md +22 -0
- data/Rakefile +27 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/ecoportal-api-v2.gemspec +34 -0
- data/lib/ecoportal/api-v2.rb +10 -0
- data/lib/ecoportal/api/common.rb +18 -0
- data/lib/ecoportal/api/common/content.rb +18 -0
- data/lib/ecoportal/api/common/content/array_model.rb +286 -0
- data/lib/ecoportal/api/common/content/class_helpers.rb +146 -0
- data/lib/ecoportal/api/common/content/client.rb +40 -0
- data/lib/ecoportal/api/common/content/collection_model.rb +279 -0
- data/lib/ecoportal/api/common/content/doc_helpers.rb +67 -0
- data/lib/ecoportal/api/common/content/double_model.rb +356 -0
- data/lib/ecoportal/api/common/content/hash_diff_patch.rb +183 -0
- data/lib/ecoportal/api/common/content/string_digest.rb +27 -0
- data/lib/ecoportal/api/common/content/wrapped_response.rb +42 -0
- data/lib/ecoportal/api/v2.rb +82 -0
- data/lib/ecoportal/api/v2/page.rb +42 -0
- data/lib/ecoportal/api/v2/page/component.rb +133 -0
- data/lib/ecoportal/api/v2/page/component/action.rb +28 -0
- data/lib/ecoportal/api/v2/page/component/action_field.rb +54 -0
- data/lib/ecoportal/api/v2/page/component/chart_field.rb +54 -0
- data/lib/ecoportal/api/v2/page/component/chart_field/frequency.rb +29 -0
- data/lib/ecoportal/api/v2/page/component/chart_field/heatmap.rb +27 -0
- data/lib/ecoportal/api/v2/page/component/chart_field/indicator.rb +26 -0
- data/lib/ecoportal/api/v2/page/component/chart_field/multiseries.rb +31 -0
- data/lib/ecoportal/api/v2/page/component/chart_field/sankey.rb +27 -0
- data/lib/ecoportal/api/v2/page/component/chart_field/serie.rb +26 -0
- data/lib/ecoportal/api/v2/page/component/chart_field/series_config.rb +23 -0
- data/lib/ecoportal/api/v2/page/component/chart_fr_field.rb +32 -0
- data/lib/ecoportal/api/v2/page/component/checklist_field.rb +49 -0
- data/lib/ecoportal/api/v2/page/component/checklist_item.rb +25 -0
- data/lib/ecoportal/api/v2/page/component/date_field.rb +34 -0
- data/lib/ecoportal/api/v2/page/component/file.rb +16 -0
- data/lib/ecoportal/api/v2/page/component/files_field.rb +13 -0
- data/lib/ecoportal/api/v2/page/component/gauge_field.rb +36 -0
- data/lib/ecoportal/api/v2/page/component/gauge_stop.rb +88 -0
- data/lib/ecoportal/api/v2/page/component/geo_field.rb +13 -0
- data/lib/ecoportal/api/v2/page/component/image.rb +16 -0
- data/lib/ecoportal/api/v2/page/component/images_field.rb +23 -0
- data/lib/ecoportal/api/v2/page/component/law_field.rb +12 -0
- data/lib/ecoportal/api/v2/page/component/number_field.rb +12 -0
- data/lib/ecoportal/api/v2/page/component/people_field.rb +25 -0
- data/lib/ecoportal/api/v2/page/component/plain_text_field.rb +15 -0
- data/lib/ecoportal/api/v2/page/component/reference_field.rb +16 -0
- data/lib/ecoportal/api/v2/page/component/rich_text_field.rb +13 -0
- data/lib/ecoportal/api/v2/page/component/selection_field.rb +78 -0
- data/lib/ecoportal/api/v2/page/component/selection_option.rb +25 -0
- data/lib/ecoportal/api/v2/page/component/signature_field.rb +25 -0
- data/lib/ecoportal/api/v2/page/component/tag_field.rb +14 -0
- data/lib/ecoportal/api/v2/page/components.rb +42 -0
- data/lib/ecoportal/api/v2/page/section.rb +59 -0
- data/lib/ecoportal/api/v2/page/sections.rb +47 -0
- data/lib/ecoportal/api/v2/page/stage.rb +29 -0
- data/lib/ecoportal/api/v2/page/stages.rb +26 -0
- data/lib/ecoportal/api/v2/pages.rb +92 -0
- data/lib/ecoportal/api/v2/pages/page_stage.rb +16 -0
- data/lib/ecoportal/api/v2/pages/stages.rb +55 -0
- data/lib/ecoportal/api/v2/people.rb +31 -0
- data/lib/ecoportal/api/v2/registers.rb +89 -0
- data/lib/ecoportal/api/v2/registers/page_result.rb +21 -0
- data/lib/ecoportal/api/v2/registers/register.rb +37 -0
- data/lib/ecoportal/api/v2/registers/stage_result.rb +14 -0
- data/lib/ecoportal/api/v2/registers/stages_result.rb +13 -0
- data/lib/ecoportal/api/v2/registers/template.rb +12 -0
- data/lib/ecoportal/api/v2/version.rb +7 -0
- metadata +254 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
module Ecoportal
|
|
2
|
+
module API
|
|
3
|
+
module Common
|
|
4
|
+
module Content
|
|
5
|
+
end
|
|
6
|
+
end
|
|
7
|
+
end
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
require 'ecoportal/api/common/content/class_helpers'
|
|
11
|
+
require 'ecoportal/api/common/content/string_digest'
|
|
12
|
+
require 'ecoportal/api/common/content/double_model'
|
|
13
|
+
require 'ecoportal/api/common/content/array_model'
|
|
14
|
+
require 'ecoportal/api/common/content/collection_model'
|
|
15
|
+
require 'ecoportal/api/common/content/doc_helpers'
|
|
16
|
+
require 'ecoportal/api/common/content/hash_diff_patch'
|
|
17
|
+
require 'ecoportal/api/common/content/client'
|
|
18
|
+
require 'ecoportal/api/common/content/wrapped_response'
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
module Ecoportal
|
|
2
|
+
module API
|
|
3
|
+
module Common
|
|
4
|
+
module Content
|
|
5
|
+
# Class to handle a plain Array embedded in a Hashed model.
|
|
6
|
+
# @note its purpose is to handle an Array of basic objects (i.e. `Date`, `String`, `Number`)
|
|
7
|
+
class ArrayModel < Content::DoubleModel
|
|
8
|
+
class TypeMismatchedComparison < Exception
|
|
9
|
+
def initialize (this: nil, that: msg = "Trying to compare objects with different behavior.")
|
|
10
|
+
if this
|
|
11
|
+
msg += " From object with 'order_matters: #{this.order_matters?}' and 'uniq: #{this.uniq?}'."
|
|
12
|
+
end
|
|
13
|
+
if that
|
|
14
|
+
msg += " To object where 'order_matters: #{that.order_matters?}' and 'uniq: #{that.uniq?}'."
|
|
15
|
+
end
|
|
16
|
+
super(msg)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
include Enumerable
|
|
21
|
+
|
|
22
|
+
class << self
|
|
23
|
+
attr_accessor :order_matters, :uniq
|
|
24
|
+
|
|
25
|
+
# @param a [ArrayModel]
|
|
26
|
+
# @param b [ArrayModel]
|
|
27
|
+
# @return [Boolean] `true` if both elements have same behaviour
|
|
28
|
+
def same_type?(a, b)
|
|
29
|
+
raise "To use this comparison both objects should be `ArrayModel`" unless a.is_a?(ArrayModel) && b.is_a?(ArrayModel)
|
|
30
|
+
(a.order_matters? == b.order_matters?) && (a.uniq? == b.uniq?)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def initialize(doc = {}, parent: self, key: nil)
|
|
36
|
+
super(doc, parent: parent, key: key)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def order_matters?; self.class.order_matters; end
|
|
40
|
+
def uniq?; self.class.uniq; end
|
|
41
|
+
|
|
42
|
+
def length; count; end
|
|
43
|
+
def empty?; count == 0; end
|
|
44
|
+
def present?; count > 0; end
|
|
45
|
+
|
|
46
|
+
def each(&block)
|
|
47
|
+
return to_enum(:each) unless block
|
|
48
|
+
_items.each(&block)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# @return [Array] the array element represented by this object
|
|
52
|
+
def _items
|
|
53
|
+
replace_doc([]) unless doc.is_a?(Array)
|
|
54
|
+
doc.tap {|d| d.uniq! if uniq?}
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# @see #_items
|
|
58
|
+
# @return [Array] a **copy** of the `Array` elements
|
|
59
|
+
def to_a
|
|
60
|
+
_items.slice(0..-1)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# @param value [Object, Array<Object>, ArrayModel] the value(s) of the new object
|
|
64
|
+
# @return [ArrayModel] a new object with the current class
|
|
65
|
+
def new_from(value)
|
|
66
|
+
self.class.new(into_a(value))
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# @return [ArrayModel] a copy of the current object
|
|
70
|
+
def dup
|
|
71
|
+
new_from(to_a)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# @return [Integer] the position of the element in the `Array`
|
|
75
|
+
def index(value)
|
|
76
|
+
_items.index(value)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Retrieves the element of a certain position
|
|
80
|
+
# @param pos [Integer] the position of the element
|
|
81
|
+
# @return [Date, String, Number]
|
|
82
|
+
def [](pos)
|
|
83
|
+
_items[pos]
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Sets the element of a certain position
|
|
87
|
+
# @param pos [Integer] the position of the element
|
|
88
|
+
# @param value [String, Date, Number] the element
|
|
89
|
+
# @return [Date, String, Number]
|
|
90
|
+
def []=(post, value)
|
|
91
|
+
_items[pos] = value
|
|
92
|
+
on_change
|
|
93
|
+
self[pos]
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Compares with an `Array` or another `ArrayModel`
|
|
97
|
+
# @param a [ArrayModel, Array]
|
|
98
|
+
def ==(a)
|
|
99
|
+
return true if self.equal?(a)
|
|
100
|
+
return false unless (a.class == self.class) || a.is_a?(Array)
|
|
101
|
+
case a
|
|
102
|
+
when Array
|
|
103
|
+
self == new_from(a)
|
|
104
|
+
when ArrayModel
|
|
105
|
+
return true if
|
|
106
|
+
raise TypeMismatchedComparison.new(this: self, that: a) unless self.class.same_type?(self, a)
|
|
107
|
+
|
|
108
|
+
if self.order_matters?
|
|
109
|
+
_items == a.to_a
|
|
110
|
+
else
|
|
111
|
+
(_items - a.to_a).empty? && (a.to_a - _items).empty?
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# @return [Boolean] `true` if `value` is present, `false` otherwise
|
|
117
|
+
def include?(value)
|
|
118
|
+
_items.include?(value)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def include_any?(*value)
|
|
122
|
+
value.any? {|v| _items.include?(v)}
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def include_all?(*value)
|
|
126
|
+
value.all? {|v| _items.include?(v)}
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# Adds an element to the subjacent `Array`
|
|
130
|
+
# @note if the class variable `uniq` is `true`, it skips duplicates
|
|
131
|
+
def <<(value)
|
|
132
|
+
_items.concat(into_a(value)).tap do |doc|
|
|
133
|
+
doc.uniq! if uniq?
|
|
134
|
+
end
|
|
135
|
+
on_change
|
|
136
|
+
self
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# @see #<<
|
|
140
|
+
def push!(value)
|
|
141
|
+
self << value
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# @see #<<
|
|
145
|
+
# @note same as #push! but for multiple elements
|
|
146
|
+
def concat!(values)
|
|
147
|
+
self << values
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
# Resets the `Array` by keeping its reference and adds the value(s)
|
|
151
|
+
# @param value [Object, Array<Object>, ArrayModel] the value(s) to be added
|
|
152
|
+
# @param values [Array]
|
|
153
|
+
def <(values)
|
|
154
|
+
_items.clear
|
|
155
|
+
self << values
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
# Clears the `Array` keeping its reference
|
|
159
|
+
def clear!
|
|
160
|
+
_items.clear
|
|
161
|
+
on_change
|
|
162
|
+
self
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
# Concat to new
|
|
166
|
+
def +(value)
|
|
167
|
+
new_from(self.to_a + into_a(value))
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
# Join
|
|
171
|
+
# @param value [Object, Array<Object>, ArrayModel] the value(s) to be joined
|
|
172
|
+
# @return [ArrayModel] a new object instance with the intersection done
|
|
173
|
+
def |(value)
|
|
174
|
+
new = new_from(value) - self
|
|
175
|
+
new_from(to_a + new.to_a)
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
# Intersect
|
|
179
|
+
# @param value [Object, Array<Object>, ArrayModel] the value(s) to be deleted
|
|
180
|
+
# @return [ArrayModel] a new object instance with the intersection done
|
|
181
|
+
def &(value)
|
|
182
|
+
self.dup.tap do |out|
|
|
183
|
+
self.dup.tap do |delta|
|
|
184
|
+
delta.delete!(*into_a(value))
|
|
185
|
+
out.delete!(*into_a(delta))
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
# Subtract
|
|
191
|
+
# @param value [Object, Array<Object>, ArrayModel] the value(s) to be deleted
|
|
192
|
+
# @return [ArrayModel] a **copy** of the object with the elements subtracted
|
|
193
|
+
def -(value)
|
|
194
|
+
self.dup.tap do |copy|
|
|
195
|
+
copy.delete!(*into_a(value))
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
# Deletes `values` from the `Array`
|
|
200
|
+
def delete!(*values)
|
|
201
|
+
values.map do |v|
|
|
202
|
+
deletion!(v)
|
|
203
|
+
end.tap do |r|
|
|
204
|
+
on_change
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
# Swaps two values' positions
|
|
209
|
+
# @note this will work with first instances when **not** `uniq?`
|
|
210
|
+
# @param val1 [Object] the first value to swap
|
|
211
|
+
# @param val2 [Object] the second value to swap
|
|
212
|
+
# @return [Integer] the new of `value1`, `nil` if it wasn't moved
|
|
213
|
+
def swap(value1, value2)
|
|
214
|
+
index(value2).tap do |dest|
|
|
215
|
+
if dest && pos = index(value1)
|
|
216
|
+
_items[dest] = value1
|
|
217
|
+
_items[pos] = value2
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
def insert_one(value, pos: NOT_USED, before: NOT_USED, after: NOT_USED)
|
|
223
|
+
i = index(value)
|
|
224
|
+
return i if (i && uniq?)
|
|
225
|
+
|
|
226
|
+
pos = case
|
|
227
|
+
when used_param?(pos)
|
|
228
|
+
pos
|
|
229
|
+
when used_param?(before)
|
|
230
|
+
index(before)
|
|
231
|
+
when used_param?(after)
|
|
232
|
+
if i = index(after)
|
|
233
|
+
i + 1
|
|
234
|
+
end
|
|
235
|
+
else
|
|
236
|
+
length
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
pos.tap do |i|
|
|
240
|
+
unless !i
|
|
241
|
+
_items.insert(pos, value)
|
|
242
|
+
on_change
|
|
243
|
+
end
|
|
244
|
+
end
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
# TODO
|
|
248
|
+
def move(value, pos: NOT_USED, before: NOT_USED, after: NOT_USED)
|
|
249
|
+
if i = index(value)
|
|
250
|
+
unless i == pos
|
|
251
|
+
|
|
252
|
+
on_change
|
|
253
|
+
end
|
|
254
|
+
pos
|
|
255
|
+
end
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
protected
|
|
259
|
+
|
|
260
|
+
def on_change
|
|
261
|
+
# to be overriden by child classes
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
private
|
|
265
|
+
|
|
266
|
+
def into_a(value)
|
|
267
|
+
raise "Can't convert to 'Array' a 'Hash', as is a key_value pair Enumerable" if value.is_a?(Hash)
|
|
268
|
+
return value.to_a.slice(0..-1) if value.is_a?(Enumerable)
|
|
269
|
+
[].push(value).compact
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
def deletion!(value)
|
|
273
|
+
if !uniq?
|
|
274
|
+
if i = _items.index(value)
|
|
275
|
+
_items.slice!(i)
|
|
276
|
+
end
|
|
277
|
+
else
|
|
278
|
+
_items.delete(value)
|
|
279
|
+
end
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
end
|
|
283
|
+
end
|
|
284
|
+
end
|
|
285
|
+
end
|
|
286
|
+
end
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
module Ecoportal
|
|
2
|
+
module API
|
|
3
|
+
module Common
|
|
4
|
+
module Content
|
|
5
|
+
module ClassHelpers
|
|
6
|
+
include Common::BaseClass
|
|
7
|
+
NOT_USED = "no_used!"
|
|
8
|
+
|
|
9
|
+
# Class resolver
|
|
10
|
+
# @note it caches the resolved `klass`es
|
|
11
|
+
# @raise [Exception] when could not resolve if `exception` is `true`
|
|
12
|
+
# @param klass [Class, String, Symbol] the class to resolve
|
|
13
|
+
# @param exception [Boolean] if it should raise exception when could not resolve
|
|
14
|
+
# @return [Class] the `Class` constant
|
|
15
|
+
def resolve_class(klass, exception: true)
|
|
16
|
+
@resolved ||= {}
|
|
17
|
+
@resolved[klass] ||=
|
|
18
|
+
case klass
|
|
19
|
+
when Class
|
|
20
|
+
klass
|
|
21
|
+
when String
|
|
22
|
+
begin
|
|
23
|
+
Kernel.const_get(klass)
|
|
24
|
+
rescue NameError => e
|
|
25
|
+
raise if exception
|
|
26
|
+
end
|
|
27
|
+
when Symbol
|
|
28
|
+
resolve_class(self.send(klass))
|
|
29
|
+
else
|
|
30
|
+
raise "Unknown class: #{klass}" if exception
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Helper to normalize `key` into a correct `ruby` **constant name**
|
|
35
|
+
# @param key [String, Symbol] to be normalized
|
|
36
|
+
# @return [String] a correct constant name
|
|
37
|
+
def to_constant(key)
|
|
38
|
+
str_name = key.to_s.strip.split(/[\-\_ ]/i).compact.map do |str|
|
|
39
|
+
str.slice(0).upcase + str.slice(1..-1).downcase
|
|
40
|
+
end.join("")
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Helper to create an instance variable `name`
|
|
44
|
+
# @param [String, Symbol] the name of the variable
|
|
45
|
+
# @reutrn [String] the name of the created instance variable
|
|
46
|
+
def instance_variable_name(name)
|
|
47
|
+
str = name.to_s
|
|
48
|
+
str = "@#{str}" unless str.start_with?("@")
|
|
49
|
+
str
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# If the class for `name` exists, it returns it. Otherwise it generates it.
|
|
53
|
+
# @param name [String, Symbol] the name of the new class
|
|
54
|
+
# @param inherits [Class] the parent class to _inherit_ from
|
|
55
|
+
# @yield [child_class] configure the new class
|
|
56
|
+
# @yieldparam child_class [Class] the new class
|
|
57
|
+
# @return [Class] the new generated class
|
|
58
|
+
def new_class(name, inherits:)
|
|
59
|
+
name = name.to_sym.freeze
|
|
60
|
+
class_name = to_constant(name)
|
|
61
|
+
full_class_name = "#{inherits}::#{class_name}"
|
|
62
|
+
|
|
63
|
+
unless target_class = resolve_class(full_class_name, exception: false)
|
|
64
|
+
target_class = Class.new(inherits)
|
|
65
|
+
self.const_set class_name, target_class
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
target_class.tap do |klass|
|
|
69
|
+
yield(klass) if block_given?
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Helper to parse a value into a `Time` object.
|
|
74
|
+
# @raise [Exception] if `exception` is `true` and could not convert
|
|
75
|
+
# @param value [String, Date] the value to convert to `Time`
|
|
76
|
+
# @param exception [Boolean] if should raise `Exception` when could not convert
|
|
77
|
+
# @return
|
|
78
|
+
def to_time(value, exception: true)
|
|
79
|
+
case value
|
|
80
|
+
when NilClass
|
|
81
|
+
value
|
|
82
|
+
when String
|
|
83
|
+
begin
|
|
84
|
+
Time.parse(value)
|
|
85
|
+
rescue ArgumentArgument => e
|
|
86
|
+
raise if exception
|
|
87
|
+
nil
|
|
88
|
+
end
|
|
89
|
+
when Date
|
|
90
|
+
Time.parse(value.to_s)
|
|
91
|
+
when Time
|
|
92
|
+
value
|
|
93
|
+
else
|
|
94
|
+
to_time(value.to_s) if value.respond_to?(:to_s)
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# Helper to determine if a paramter has been used
|
|
99
|
+
# @note to effectivelly use this helper, you should initialize your target
|
|
100
|
+
# paramters with the constant `NOT_USED`
|
|
101
|
+
# @param val [] the value of the paramter
|
|
102
|
+
# @return [Boolean] `true` if value other than `NOT_USED`, `false` otherwise
|
|
103
|
+
def used_param?(val)
|
|
104
|
+
val != NOT_USED
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Keeps track on class instance variables that should be inherited by child classes.
|
|
108
|
+
# @note
|
|
109
|
+
# - subclasses will inherit the value as is at that moment
|
|
110
|
+
# - any change afterwards will be only on the specific class (in line with class instance variables)
|
|
111
|
+
# - adapted from https://stackoverflow.com/a/10729812/4352306
|
|
112
|
+
# TODO: this separates the logic of the method to the instance var. Think if would be possible to join them somehow.
|
|
113
|
+
def inheritable_class_vars(*vars)
|
|
114
|
+
@inheritable_class_vars ||= [:inheritable_class_vars]
|
|
115
|
+
@inheritable_class_vars += vars
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# Builds the attr_reader and attr_writer of `attrs` and registers the associated instance variable as inheritable.
|
|
119
|
+
def inheritable_attrs(*attrs)
|
|
120
|
+
attrs.each do |attr|
|
|
121
|
+
class_eval %(
|
|
122
|
+
class << self; attr_accessor :#{attr} end
|
|
123
|
+
)
|
|
124
|
+
end
|
|
125
|
+
inheritable_class_vars(*attrs)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# This callback method is called whenever a subclass of the current class is created.
|
|
129
|
+
# @note
|
|
130
|
+
# - values of the instance variables are copied as they are (no dups or clones)
|
|
131
|
+
# - the above means: avoid methods that change the state of the mutable object on it
|
|
132
|
+
# - mutating methods would reflect the changes on other classes as well
|
|
133
|
+
# - therefore, `freeze` will be called on the values that are inherited.
|
|
134
|
+
def inherited(subclass)
|
|
135
|
+
inheritable_class_vars.each do |var|
|
|
136
|
+
instance_var = instance_variable_name(var)
|
|
137
|
+
value = instance_variable_get(instance_var)
|
|
138
|
+
subclass.instance_variable_set(instance_var, value.freeze)
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
end
|