openhab-jrubyscripting 5.0.0.rc1 → 5.0.0.rc3

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.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/lib/openhab/core/entity_lookup.rb +1 -12
  3. data/lib/openhab/core/items/generic_item.rb +15 -7
  4. data/lib/openhab/core/items/metadata/hash.rb +81 -39
  5. data/lib/openhab/core/items/metadata/namespace_hash.rb +17 -19
  6. data/lib/openhab/core/items/metadata/provider.rb +48 -0
  7. data/lib/openhab/core/items/persistence.rb +2 -0
  8. data/lib/openhab/core/items/provider.rb +40 -0
  9. data/lib/openhab/core/items/proxy.rb +10 -0
  10. data/lib/openhab/core/items/registry.rb +16 -7
  11. data/lib/openhab/core/items/semantics/enumerable.rb +6 -4
  12. data/lib/openhab/core/items/state_storage.rb +3 -3
  13. data/lib/openhab/core/profile_factory.rb +3 -1
  14. data/lib/openhab/core/provider.rb +223 -0
  15. data/lib/openhab/core/registry.rb +30 -0
  16. data/lib/openhab/core/rules/provider.rb +25 -0
  17. data/lib/openhab/core/rules/registry.rb +76 -0
  18. data/lib/openhab/core/rules/rule.rb +150 -0
  19. data/lib/openhab/core/rules.rb +25 -0
  20. data/lib/openhab/core/script_handling.rb +50 -0
  21. data/lib/openhab/core/things/links/provider.rb +40 -0
  22. data/lib/openhab/core/things/provider.rb +25 -0
  23. data/lib/openhab/core/things/proxy.rb +10 -0
  24. data/lib/openhab/core/things/registry.rb +25 -2
  25. data/lib/openhab/core/timer.rb +17 -7
  26. data/lib/openhab/core/types/quantity_type.rb +5 -2
  27. data/lib/openhab/core/types.rb +1 -1
  28. data/lib/openhab/core.rb +3 -30
  29. data/lib/openhab/core_ext/java/class.rb +34 -0
  30. data/lib/openhab/core_ext/java/list.rb +436 -0
  31. data/lib/openhab/core_ext/java/local_time.rb +2 -1
  32. data/lib/openhab/core_ext/java/map.rb +66 -0
  33. data/lib/openhab/core_ext/java/month.rb +2 -1
  34. data/lib/openhab/core_ext/java/zoned_date_time.rb +1 -2
  35. data/lib/openhab/core_ext/ruby/date.rb +2 -0
  36. data/lib/openhab/core_ext/ruby/date_time.rb +53 -0
  37. data/lib/openhab/core_ext/ruby/time.rb +88 -86
  38. data/lib/openhab/dsl/events/watch_event.rb +1 -1
  39. data/lib/openhab/dsl/items/builder.rb +38 -100
  40. data/lib/openhab/dsl/items/ensure.rb +6 -2
  41. data/lib/openhab/dsl/items/timed_command.rb +10 -11
  42. data/lib/openhab/dsl/rules/automation_rule.rb +36 -13
  43. data/lib/openhab/dsl/rules/builder.rb +126 -8
  44. data/lib/openhab/dsl/rules/name_inference.rb +0 -5
  45. data/lib/openhab/dsl/rules/terse.rb +1 -2
  46. data/lib/openhab/dsl/rules/triggers/changed.rb +7 -4
  47. data/lib/openhab/dsl/rules/triggers/conditions/duration.rb +17 -53
  48. data/lib/openhab/dsl/rules/triggers/conditions/proc.rb +0 -3
  49. data/lib/openhab/dsl/rules/triggers/cron/cron.rb +1 -1
  50. data/lib/openhab/dsl/rules/triggers/trigger.rb +1 -1
  51. data/lib/openhab/dsl/rules/triggers/updated.rb +7 -3
  52. data/lib/openhab/dsl/rules/triggers/watch/watch_handler.rb +1 -1
  53. data/lib/openhab/dsl/rules.rb +0 -21
  54. data/lib/openhab/dsl/script_handling.rb +0 -49
  55. data/lib/openhab/dsl/things/builder.rb +8 -31
  56. data/lib/openhab/dsl/thread_local.rb +3 -2
  57. data/lib/openhab/dsl/timer_manager.rb +16 -8
  58. data/lib/openhab/dsl/version.rb +1 -1
  59. data/lib/openhab/dsl.rb +137 -120
  60. data/lib/openhab/log.rb +3 -3
  61. data/lib/openhab/rspec/example_group.rb +42 -0
  62. data/lib/openhab/rspec/helpers.rb +33 -27
  63. data/lib/openhab/rspec/hooks.rb +17 -23
  64. data/lib/openhab/rspec/karaf.rb +45 -27
  65. data/lib/openhab/rspec/mocks/synchronous_executor.rb +11 -4
  66. data/lib/openhab/rspec/mocks/timer.rb +7 -1
  67. data/lib/openhab/rspec/suspend_rules.rb +4 -2
  68. metadata +30 -3
  69. data/lib/openhab/rspec/mocks/metadata_provider.rb +0 -75
@@ -24,6 +24,8 @@ module OpenHAB
24
24
  end
25
25
  alias_method :include?, :[]
26
26
  alias_method :key?, :[]
27
+ # @deprecated
28
+ alias_method :has_key?, :[]
27
29
 
28
30
  #
29
31
  # Explicit conversion to array
@@ -34,11 +36,32 @@ module OpenHAB
34
36
  $things.all.map { |thing| Proxy.new(thing) }
35
37
  end
36
38
 
39
+ #
37
40
  # Enter the Thing Builder DSL.
41
+ # @param (see Core::Provider.current)
38
42
  # @yield Block executed in the context of a {DSL::Things::Builder}.
39
43
  # @return [Object] The result of the block.
40
- def build(&block)
41
- DSL::Things::Builder.new.instance_eval(&block)
44
+ #
45
+ def build(preferred_provider = nil, &block)
46
+ DSL::Things::Builder.new(preferred_provider).instance_eval(&block)
47
+ end
48
+
49
+ #
50
+ # Remove a Thing.
51
+ #
52
+ # The thing must be a managed thing (typically created by Ruby or in the UI).
53
+ #
54
+ # @param [String, Thing, ThingUID] thing_uid
55
+ # @return [Thing, nil] The removed item, if found.
56
+ def remove(thing_uid)
57
+ thing_uid = thing.uid if thing_uid.is_a?(Thing)
58
+ thing_uid = ThingUID.new(thing_uid) if thing_uid.is_a?(String)
59
+ provider = Provider.registry.provider_for(thing_uid)
60
+ unless provider.is_a?(org.openhab.core.common.registry.ManagedProvider)
61
+ raise "Cannot remove thing #{thing_uid} from non-managed provider #{provider.inspect}"
62
+ end
63
+
64
+ provider.remove(thing_uid)
42
65
  end
43
66
  end
44
67
  end
@@ -35,7 +35,6 @@ module OpenHAB
35
35
  # @return [Object, nil]
36
36
  attr_accessor :id
37
37
 
38
- # @!visibility private
39
38
  # @!visibility private
40
39
  attr_reader :block
41
40
 
@@ -84,6 +83,7 @@ module OpenHAB
84
83
  # @return [self]
85
84
  #
86
85
  def reschedule(time = nil)
86
+ Thread.current[:openhab_rescheduled_timer] = true if Thread.current[:openhab_rescheduled_timer] == self
87
87
  DSL.timers.add(self)
88
88
  @timer.reschedule(new_execution_time(time || @time))
89
89
  self
@@ -96,6 +96,18 @@ module OpenHAB
96
96
  #
97
97
  def cancel
98
98
  DSL.timers.delete(self)
99
+ cancel!
100
+ end
101
+
102
+ #
103
+ # Cancel the timer but do not remove self from the timer manager
104
+ #
105
+ # To be used internally by {TimerManager} from inside ConcurrentHashMap's compute blocks
106
+ #
107
+ # @return [true,false] True if cancel was successful, false otherwise
108
+ #
109
+ # @!visibility private
110
+ def cancel!
99
111
  @timer.cancel
100
112
  end
101
113
 
@@ -107,12 +119,10 @@ module OpenHAB
107
119
  # @return [void]
108
120
  #
109
121
  def execute
110
- last_execution_time = execution_time
111
- DSL::ThreadLocal.thread_local(**@thread_locals) do
112
- @block.call(self)
113
- end
114
- # don't remove ourselves if we were rescheduled in the block
115
- DSL.timers.delete(self) if execution_time == last_execution_time
122
+ Thread.current[:openhab_rescheduled_timer] = self
123
+ DSL::ThreadLocal.thread_local(**@thread_locals) { @block.call(self) }
124
+ DSL.timers.delete(self) unless Thread.current[:openhab_rescheduled_timer] == true
125
+ Thread.current[:openhab_rescheduled_timer] = nil
116
126
  end
117
127
 
118
128
  #
@@ -15,6 +15,9 @@ module OpenHAB
15
15
  # framework in OpenHAB. It is represented as a decimal number with a unit.
16
16
  # You can construct a {QuantityType} object by using the pipe operator with any Numeric.
17
17
  #
18
+ # @see OpenHAB::DSL.unit unit: Implicit unit conversions
19
+ # @see OpenHAB::CoreExt::Ruby::QuantityTypeConversion Convert Numeric to QuantityType
20
+ #
18
21
  # @example QuantityTypes can perform math operations between them.
19
22
  # (50 | "°F") + (-25 | "°F") # => 25.0 °F
20
23
  # (100 | "°F") / (2 | "°F") # => 50
@@ -141,7 +144,7 @@ module OpenHAB
141
144
  return compare_to(QuantityType.new(other, unit))
142
145
  end
143
146
 
144
- return nil # don"t allow comparison with numeric outside a unit block
147
+ return nil # don't allow comparison with numeric outside a unit block
145
148
  end
146
149
 
147
150
  return nil unless other.respond_to?(:coerce)
@@ -308,7 +311,7 @@ module OpenHAB
308
311
  def multiply_quantity(other)
309
312
  lhs = deunitize
310
313
  rhs = other.deunitize
311
- # reverse the arguments if it's multiplication and the LHS isn"t a QuantityType
314
+ # reverse the arguments if it's multiplication and the LHS isn't a QuantityType
312
315
  lhs, rhs = rhs, lhs if lhs.is_a?(java.math.BigDecimal)
313
316
  # what a waste... using a QuantityType to multiply two dimensionless quantities
314
317
  # have to make sure lhs is still a QuantityType in order to return a new
@@ -13,7 +13,7 @@ module OpenHAB
13
13
  # Types are the specific data types that commands and states are. They can be
14
14
  # sent to items, be the current state of an item, or be the `command`, `state`,
15
15
  # and `was` field of various
16
- # {group::OpenHAB::DSL::Rules::Builder::Triggers triggers}.
16
+ # {group::OpenHAB::DSL::Rules::BuilderDSL::Triggers triggers}.
17
17
  # Some types have additional useful methods.
18
18
  #
19
19
  module Types
data/lib/openhab/core.rb CHANGED
@@ -1,5 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # several classes rely on this, so force it to load earlier
4
+ require_relative "core/provider"
5
+
3
6
  Dir[File.expand_path("core/**/*.rb", __dir__)].sort.each do |f|
4
7
  require f
5
8
  end
@@ -42,20 +45,6 @@ module OpenHAB
42
45
  Pathname.new(org.openhab.core.OpenHAB.config_folder)
43
46
  end
44
47
 
45
- #
46
- # JRuby isn't respecting $RUBYLIB when run embedded inside of OpenHAB, so do it manually
47
- #
48
- # @return [void]
49
- #
50
- # @!visibility private
51
- def add_rubylib_to_load_path
52
- ENV["RUBYLIB"]&.split(File::PATH_SEPARATOR)&.each do |path|
53
- next if path.empty?
54
-
55
- $LOAD_PATH.unshift(path) unless $LOAD_PATH.include?(path)
56
- end
57
- end
58
-
59
48
  #
60
49
  # @!attribute [r] automation_manager
61
50
  # @return [org.openhab.core.automation.module.script.rulesupport.shared.ScriptedAutomationManager]
@@ -64,22 +53,6 @@ module OpenHAB
64
53
  def automation_manager
65
54
  $scriptExtension.get("automationManager")
66
55
  end
67
-
68
- #
69
- # @!attribute [r] rule_registry
70
- # @return [org.openhab.core.automation.RuleRegistry] The OpenHAB rule registry
71
- #
72
- def rule_registry
73
- $scriptExtension.get("ruleRegistry")
74
- end
75
-
76
- #
77
- # @!attribute [r] rule_manager
78
- # @return [org.openhab.core.automation.RuleManager] The OpenHAB rule manager/engine
79
- #
80
- def rule_manager
81
- @rule_manager ||= OSGi.service("org.openhab.core.automation.RuleManager")
82
- end
83
56
  end
84
57
  end
85
58
  end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OpenHAB
4
+ module CoreExt
5
+ module Java
6
+ Class = java.lang.Class
7
+
8
+ # Extensions to Class
9
+ class Class
10
+ #
11
+ # `self`, all superclasses and interfaces, recursively.
12
+ #
13
+ # @return [Array<Class>]
14
+ #
15
+ def ancestors
16
+ ([self] +
17
+ Array(superclass&.ancestors) +
18
+ interfaces.flat_map(&:ancestors)).uniq
19
+ end
20
+
21
+ #
22
+ # `self`, all superclasses and interfaces, recursively.
23
+ #
24
+ # @return [Array<java.reflect.Type>]
25
+ #
26
+ def generic_ancestors
27
+ ancestors.flat_map do |klass|
28
+ Array(klass.generic_superclass) + klass.generic_interfaces
29
+ end.uniq
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,436 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @!visibility private
4
+ module Java::JavaUtil::List # rubocop:disable Style/ClassAndModuleChildren
5
+ extend Forwardable
6
+
7
+ def_delegators :to_a,
8
+ :&,
9
+ :*,
10
+ :|,
11
+ :bsearch_index,
12
+ :difference,
13
+ :flatten,
14
+ :intersection,
15
+ :pack,
16
+ :product,
17
+ :repeated_combination,
18
+ :repeated_permutation,
19
+ :reverse,
20
+ :rotate,
21
+ :sample,
22
+ :shelljoin,
23
+ :shuffle,
24
+ :transpose,
25
+ :union
26
+
27
+ def assoc(obj)
28
+ find { |v| (v.is_a?(Array) || v.is_a?(self.class)) && v[0] == obj }
29
+ end
30
+
31
+ def at(index)
32
+ self[index]
33
+ end
34
+
35
+ def bsearch(&block)
36
+ raise NotImplementedError unless block
37
+
38
+ r = bsearch_index(&block)
39
+ self[r] if r
40
+ end
41
+
42
+ def combination(n, &block) # rubocop:disable Naming/MethodParameterName
43
+ r = to_a.combination(n, &block)
44
+ block ? self : r
45
+ end
46
+
47
+ def compact
48
+ reject(&:nil?)
49
+ end
50
+
51
+ def compact!
52
+ reject!(&:nil?)
53
+ end
54
+
55
+ def concat(*other_arrays)
56
+ other_arrays.each { |array| add_all(array) }
57
+ self
58
+ end
59
+
60
+ def deconstruct
61
+ self
62
+ end
63
+
64
+ def delete(obj)
65
+ last = nil
66
+ found = false
67
+ loop do
68
+ i = index(obj)
69
+ break if i.nil?
70
+
71
+ found = true
72
+ last = remove(i)
73
+ end
74
+
75
+ return yield(obj) if !found && block_given?
76
+
77
+ last
78
+ end
79
+
80
+ def delete_at(index)
81
+ index = length + index if index.negative?
82
+ return if index.negative? || index >= length
83
+
84
+ remove(index)
85
+ end
86
+
87
+ def delete_if
88
+ raise NotImplementedError unless block_given?
89
+
90
+ it = list_iterator
91
+ while it.has_next? # rubocop:disable Style/WhileUntilModifier
92
+ it.remove if yield(it.next)
93
+ end
94
+ self
95
+ end
96
+
97
+ def dig(index, *identifiers)
98
+ return self[index] if identifiers.empty?
99
+
100
+ self[index]&.dig(*identifiers)
101
+ end
102
+
103
+ def each_index(&block)
104
+ r = (0...length)
105
+ return r.each unless block
106
+
107
+ r.each(&block)
108
+ self
109
+ end
110
+
111
+ def fetch(index, *default_value)
112
+ if default_value.length > 1
113
+ raise ArgumentError,
114
+ "wrong number of arguments calling `fetch` (given #{default_value.length - 1}, expected 1..2)"
115
+ end
116
+
117
+ original_index = index
118
+ index = length + index if index.negative?
119
+ return self[index] if index >= 0 && index < length
120
+
121
+ return default_value.first unless default_value.empty?
122
+ return yield(original_index) if block_given?
123
+
124
+ raise IndexError, "index #{index} out of list"
125
+ end
126
+
127
+ def fill(*args)
128
+ if block_given?
129
+ unless (0..2).cover?(args.length)
130
+ raise ArgumentError,
131
+ "wrong number of arguments calling `fill` (given #{args.length}, expected 1..3)"
132
+ end
133
+ else
134
+ unless (1..3).cover?(args.length)
135
+ raise ArgumentError,
136
+ "wrong number of arguments calling `fill` (given #{args.length}, expected 1..2)"
137
+ end
138
+ end
139
+
140
+ obj = args.shift unless block_given?
141
+
142
+ if args.length == 1 && args.first.is_a?(Range)
143
+ range = args.first
144
+
145
+ range = Range.new(length + range.begin, range.end, range.exclude_end?) if range.begin.negative?
146
+ range = Range.new(range.begin, length + range.end, range.exclude_end?) if range.end&.negative?
147
+ return self if range.begin.negative? || (range.end && range.end < range.begin)
148
+ else
149
+ first, count = *args
150
+ return self if count&.negative?
151
+
152
+ first ||= 0
153
+
154
+ first = length + first if first.negative?
155
+ range = count ? first...(first + count) : first..
156
+ end
157
+
158
+ add(nil) while length < range.begin && count
159
+
160
+ start = range.begin
161
+ start = 0 if start.negative?
162
+ start = length if start > length
163
+ it = list_iterator(start)
164
+
165
+ while range.cover?(it.next_index)
166
+ break if range.end.nil? && !it.has_next?
167
+
168
+ obj = yield(it.next_index) if block_given?
169
+ if it.has_next?
170
+ it.next
171
+ it.set(obj)
172
+ else
173
+ it.add(obj)
174
+ end
175
+ end
176
+
177
+ self
178
+ end
179
+
180
+ def flatten!(*args)
181
+ if args.length > 1
182
+ raise ArgumentError,
183
+ "wrong number of arguments calling `flatten` (given #{args.length}, expect 0..1)"
184
+ end
185
+
186
+ it = list_iterator
187
+
188
+ args = [args.first - 1] unless args.empty?
189
+ done = args.first == 0 # rubocop:disable Style/NumericPredicate
190
+
191
+ changed = false
192
+ while it.has_next?
193
+ element = it.next
194
+ next unless element.respond_to?(:to_ary)
195
+
196
+ changed = true
197
+ it.remove
198
+ arr = element.to_ary
199
+ arr = arr.flatten(*args) unless done
200
+ arr.each do |e|
201
+ it.add(e)
202
+ end
203
+ end
204
+ changed ? self : nil
205
+ end
206
+
207
+ def insert(index, *objects)
208
+ return self if objects.empty?
209
+
210
+ raise IndexError, "index #{index} too small for list, minimum: #{-length}" if index < -length
211
+
212
+ index = length + index + 1 if index.negative?
213
+
214
+ add(nil) while length < index
215
+ add_all(index, objects)
216
+ self
217
+ end
218
+
219
+ def intersect?(other_ary)
220
+ !(self & other_ary).empty?
221
+ end
222
+
223
+ def keep_if?
224
+ raise NotImplementedError unless block_given?
225
+
226
+ it = list_iterator
227
+ while it.has_next? # rubocop:disable Style/WhileUntilModifier
228
+ it.remove unless yield(it.next)
229
+ end
230
+ self
231
+ end
232
+
233
+ def map!(&block)
234
+ raise NotImplementedError unless block
235
+
236
+ replace_all(&block)
237
+ self
238
+ end
239
+
240
+ def permutation(n, &block) # rubocop:disable Naming/MethodParameterName
241
+ r = to_a.permutation(n, &block)
242
+ block ? self : r
243
+ end
244
+
245
+ def pop(*args)
246
+ if args.length > 1
247
+ raise ArgumentError,
248
+ "wrong number of arguments calling `pop` (given #{args.length}, expected 0..1)"
249
+ end
250
+
251
+ if args.empty?
252
+ return if empty?
253
+
254
+ return remove(length - 1)
255
+ end
256
+
257
+ count = args.first
258
+ start = [length - count, 0].max
259
+ result = self[start..-1].to_a # rubocop:disable Style/SlicingWithRange
260
+ it = list_iterator(start)
261
+ while it.has_next?
262
+ it.next
263
+ it.remove
264
+ end
265
+ result
266
+ end
267
+
268
+ def push(*objects)
269
+ add_all(objects)
270
+ self
271
+ end
272
+ alias_method :append, :push
273
+
274
+ def rassoc(obj)
275
+ find { |v| (v.is_a?(Array) || v.is_a?(self.class)) && v[1] == obj }
276
+ end
277
+
278
+ def reject!
279
+ raise NotImplementedError unless block_given?
280
+
281
+ it = list_iterator
282
+ changed = false
283
+ while it.has_next
284
+ if yield(it.next)
285
+ changed = true
286
+ it.remove
287
+ end
288
+ end
289
+ self if changed
290
+ end
291
+
292
+ def repeated_combination(n, &block) # rubocop:disable Naming/MethodParameterName
293
+ r = to_a.repeated_combination(n, &block)
294
+ block ? self : r
295
+ end
296
+
297
+ def repeated_permutation(n, &block) # rubocop:disable Naming/MethodParameterName
298
+ r = to_a.repeated_permutation(n, &block)
299
+ block ? self : r
300
+ end
301
+
302
+ def replace(other_array)
303
+ clear
304
+ add_all(other_array)
305
+ self
306
+ end
307
+
308
+ def reverse!
309
+ replace(reverse)
310
+ self
311
+ end
312
+
313
+ def rotate!(count = 1)
314
+ count = count % length
315
+ push(*shift(count))
316
+ self
317
+ end
318
+
319
+ def select!
320
+ raise NotImplementedError unless block_given?
321
+
322
+ it = list_iterator
323
+ changed = false
324
+ while it.has_next?
325
+ unless yield(it.next)
326
+ changed = true
327
+ it.remove
328
+ end
329
+ end
330
+ self if changed
331
+ end
332
+
333
+ def shift(*args)
334
+ if args.length > 1
335
+ raise ArgumentError,
336
+ "wrong number of arguments calling `shift` (given #{args.length}, expected 0..1)"
337
+ end
338
+
339
+ if args.empty?
340
+ return if empty?
341
+
342
+ return remove(0)
343
+ end
344
+
345
+ count = args.first
346
+ result = self[0...count].to_a
347
+ it = list_iterator
348
+ count.times do
349
+ break unless it.has_next?
350
+
351
+ it.next
352
+ it.remove
353
+ end
354
+ result
355
+ end
356
+
357
+ def shuffle!(*args)
358
+ replace(shuffle(*args))
359
+ end
360
+
361
+ def slice(*args)
362
+ self[*args]
363
+ end
364
+
365
+ def slice!(*args)
366
+ unless (1..2).cover?(args.length)
367
+ raise ArgumentError,
368
+ "wrong number of arguments calling `slice!` (given #{args.length}, expected 1..2)"
369
+ end
370
+
371
+ return delete_at(args.first) if args.length == 1 && !args.first.is_a?(Range)
372
+
373
+ start = args.first
374
+ start = start.begin if start.is_a?(Range)
375
+ start = length + start if start.negative?
376
+ return nil if start.negative? || start >= length
377
+
378
+ result = slice(*args).to_a
379
+
380
+ it = list_iterator(start)
381
+ result.length.times do
382
+ it.next
383
+ it.remove
384
+ end
385
+ result
386
+ end
387
+
388
+ def sort_by!
389
+ raise NotImplementedError unless block_given?
390
+
391
+ sort { |a, b| (yield a) <=> (yield b) }
392
+ self
393
+ end
394
+
395
+ def uniq!
396
+ seen = Set.new
397
+
398
+ it = list_iterator
399
+ changed = false
400
+ while it.has_next?
401
+ n = it.next
402
+ n = yield(n) if block_given?
403
+ if seen.include?(n)
404
+ changed = true
405
+ it.remove
406
+ end
407
+ seen << n
408
+ end
409
+ self if changed
410
+ end
411
+
412
+ def unshift(*objects)
413
+ add_all(0, objects)
414
+ self
415
+ end
416
+ alias_method :prepend, :unshift
417
+
418
+ def values_at(*indexes)
419
+ result = []
420
+ indexes.each do |index|
421
+ if index.is_a?(Range)
422
+ partial_result = self[index]
423
+ result.concat(partial_result)
424
+ result.fill(nil, result.length, index.count - partial_result.length)
425
+ else
426
+ index = length + index if index.negative?
427
+ result << if index.negative? || index >= length
428
+ nil
429
+ else
430
+ self[index]
431
+ end
432
+ end
433
+ end
434
+ result
435
+ end
436
+ end
@@ -33,7 +33,7 @@ module OpenHAB
33
33
  # end
34
34
  #
35
35
  class LocalTime
36
- include Time
36
+ # @!parse include Time
37
37
 
38
38
  # @!visibility private
39
39
  class << self
@@ -104,3 +104,4 @@ module OpenHAB
104
104
  end
105
105
 
106
106
  LocalTime = OpenHAB::CoreExt::Java::LocalTime unless Object.const_defined?(:LocalTime)
107
+ java.time.LocalTime.include(OpenHAB::CoreExt::Java::Time)