openhab-jrubyscripting 5.0.0.rc1 → 5.0.0.rc2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) 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 +2 -2
  4. data/lib/openhab/core/items/metadata/hash.rb +64 -5
  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/provider.rb +40 -0
  8. data/lib/openhab/core/items/proxy.rb +10 -0
  9. data/lib/openhab/core/items/registry.rb +16 -7
  10. data/lib/openhab/core/items/state_storage.rb +3 -3
  11. data/lib/openhab/core/profile_factory.rb +1 -1
  12. data/lib/openhab/core/provider.rb +216 -0
  13. data/lib/openhab/core/registry.rb +30 -0
  14. data/lib/openhab/core/script_handling.rb +50 -0
  15. data/lib/openhab/core/things/links/provider.rb +40 -0
  16. data/lib/openhab/core/things/provider.rb +25 -0
  17. data/lib/openhab/core/things/proxy.rb +10 -0
  18. data/lib/openhab/core/things/registry.rb +25 -2
  19. data/lib/openhab/core/timer.rb +12 -0
  20. data/lib/openhab/core/types/quantity_type.rb +5 -2
  21. data/lib/openhab/core.rb +3 -14
  22. data/lib/openhab/core_ext/java/class.rb +34 -0
  23. data/lib/openhab/core_ext/java/local_time.rb +2 -1
  24. data/lib/openhab/core_ext/java/month.rb +2 -1
  25. data/lib/openhab/dsl/items/builder.rb +30 -97
  26. data/lib/openhab/dsl/rules/builder.rb +27 -0
  27. data/lib/openhab/dsl/rules/triggers/changed.rb +7 -4
  28. data/lib/openhab/dsl/rules/triggers/cron/cron.rb +1 -1
  29. data/lib/openhab/dsl/rules/triggers/trigger.rb +1 -1
  30. data/lib/openhab/dsl/rules/triggers/updated.rb +7 -3
  31. data/lib/openhab/dsl/rules.rb +1 -1
  32. data/lib/openhab/dsl/script_handling.rb +0 -49
  33. data/lib/openhab/dsl/things/builder.rb +8 -31
  34. data/lib/openhab/dsl/thread_local.rb +1 -0
  35. data/lib/openhab/dsl/timer_manager.rb +13 -7
  36. data/lib/openhab/dsl/version.rb +1 -1
  37. data/lib/openhab/dsl.rb +132 -22
  38. data/lib/openhab/log.rb +1 -1
  39. data/lib/openhab/rspec/helpers.rb +8 -25
  40. data/lib/openhab/rspec/hooks.rb +15 -18
  41. data/lib/openhab/rspec/mocks/timer.rb +5 -0
  42. metadata +9 -3
  43. data/lib/openhab/rspec/mocks/metadata_provider.rb +0 -75
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cd7a4eed6a2398fd34734d9b3dc15a8f5e2bcc74f7309aede27be29501c21698
4
- data.tar.gz: a1f70554ada415e7de0325ea259ac9edcad48355ef6000a4877057fa06b343ce
3
+ metadata.gz: 0e925ebd72648fa8efb76592f6053d12f2fe9151173fa91d3f47a2d298f268fc
4
+ data.tar.gz: 6d84217a8505a72e2da686188a741d6644eee645255595d5d2cf455a2840e015
5
5
  SHA512:
6
- metadata.gz: f27aa8940df9441a5318c32d1c0d84f15fdd70b2336cf95dd09383b73b97d14bbc7c924ba3e3df24f48d5f289d410ec1d6d0df9f99a40141ac34d88152e9a76a
7
- data.tar.gz: c369de38091c4486a492b88ef990537b5a4cc667becca6be5a99a56227a8a2b0339b14e9ce1e11e6e73b56d8b055d3876917916ee7ec52b66c5b23e85b33a95b
6
+ metadata.gz: 5330bd233b45839cf1780815e86d170ff8a33b4093debfe85cae7e09e631d7a14c7bb2c7e84500da6a41fd0b89f81a160e4279659312323e6fb207bd0da6e632
7
+ data.tar.gz: 28f42c9a625aa33ef258f4d789e9fe116a1bf36e63bc58e2574d1a884ed8bde74bac03484566abd04909462ec4c9bdef543973416a2420fa02fea274122e3889
@@ -72,7 +72,7 @@ module OpenHAB
72
72
  logger.trace("Looking up thing '#{uid}'")
73
73
  uid = uid.to_s if uid.is_a?(Symbol)
74
74
 
75
- uid = generate_thing_uid(uid) unless uid.is_a?(org.openhab.core.thing.ThingUID)
75
+ uid = Things::ThingUID.new(uid) unless uid.is_a?(Things::ThingUID)
76
76
  thing = $things.get(uid)
77
77
  return unless thing
78
78
 
@@ -117,17 +117,6 @@ module OpenHAB
117
117
  item = $ir.get(name)
118
118
  Items::Proxy.new(item) unless item.nil?
119
119
  end
120
-
121
- #
122
- # Returns a ThingUID given a string like object
123
- #
124
- # @!visibility private
125
- #
126
- # @return [Things::ThingUID]
127
- #
128
- def self.generate_thing_uid(uid)
129
- org.openhab.core.thing.ThingUID.new(*uid.split(":"))
130
- end
131
120
  end
132
121
  end
133
122
  end
@@ -73,7 +73,7 @@ module OpenHAB
73
73
  def command(command)
74
74
  command = format_command(command)
75
75
  logger.trace "Sending Command #{command} to #{name}"
76
- org.openhab.core.model.script.actions.BusEvent.sendCommand(self, command)
76
+ $events.send_command(self, command)
77
77
  self
78
78
  end
79
79
 
@@ -93,7 +93,7 @@ module OpenHAB
93
93
  def update(state)
94
94
  state = format_update(state)
95
95
  logger.trace "Sending Update #{state} to #{name}"
96
- org.openhab.core.model.script.actions.BusEvent.postUpdate(self, state)
96
+ $events.post_update(self, state)
97
97
  self
98
98
  end
99
99
 
@@ -15,6 +15,8 @@ module OpenHAB
15
15
  #
16
16
  # @!attribute [rw] value
17
17
  # @return [String] The main value for the metadata namespace.
18
+ # @!attribute [r] namespace
19
+ # @return [String]
18
20
  #
19
21
  class Hash
20
22
  java_import org.openhab.core.items.Metadata
@@ -58,6 +60,8 @@ module OpenHAB
58
60
  :value?
59
61
  def_delegators :to_h, :invert, :merge, :transform_keys, :transform_values
60
62
 
63
+ def_delegator :uid, :namespace
64
+
61
65
  class << self
62
66
  # @!visibility private
63
67
  def from_item(item_name, namespace, value)
@@ -72,7 +76,7 @@ module OpenHAB
72
76
 
73
77
  [value.first, (value.last || {}).transform_keys(&:to_s)]
74
78
  when ::Hash then ["", value.transform_keys(&:to_s)]
75
- else [value, {}]
79
+ else [value.to_s, {}]
76
80
  end
77
81
  new(Metadata.new(org.openhab.core.items.MetadataKey.new(namespace.to_s, item_name), *value))
78
82
  end
@@ -108,13 +112,24 @@ module OpenHAB
108
112
  end
109
113
 
110
114
  # @!visibility private
111
- def create
112
- NamespaceHash.registry.add(@metadata) if attached?
115
+ def commit
116
+ return unless attached?
117
+
118
+ javaify
119
+ provider.update(@metadata)
113
120
  end
114
121
 
115
122
  # @!visibility private
116
- def commit
117
- NamespaceHash.registry.update(@metadata) if attached?
123
+ def create_or_update
124
+ return unless attached?
125
+
126
+ javaify
127
+ (p = provider).get(uid) ? p.update(@metadata) : p.add(@metadata)
128
+ end
129
+
130
+ # @!visibility private
131
+ def remove
132
+ provider.remove(uid)
118
133
  end
119
134
 
120
135
  # @!visibility private
@@ -383,6 +398,50 @@ module OpenHAB
383
398
  [value, to_h].inspect
384
399
  end
385
400
  alias_method :to_s, :inspect
401
+
402
+ #
403
+ # @raise [RuntimeError] if the provider is not a
404
+ # {org.openhab.core.common.registry.ManagedProvider ManagedProvider} that can be updated.
405
+ # @return [org.openhab.core.common.registry.ManagedProvider]
406
+ #
407
+ def provider
408
+ preferred_provider = Provider.current(
409
+ Thread.current[:openhab_providers]&.dig(:metadata_items, uid.item_name) ||
410
+ Thread.current[:openhab_providers]&.dig(:metadata_namespaces, uid.namespace),
411
+ self
412
+ )
413
+
414
+ if attached?
415
+ provider = Provider.registry.provider_for(uid)
416
+ return preferred_provider unless provider
417
+
418
+ unless provider.is_a?(org.openhab.core.common.registry.ManagedProvider)
419
+ raise FrozenError, "Cannot modify metadata from provider #{provider.inspect}"
420
+ end
421
+
422
+ if preferred_provider != provider
423
+ logger.warn("Provider #{preferred_provider.inspect} cannot be used with #{uid}; " \
424
+ "reverting to provider #{provider.inspect}. " \
425
+ "This may cause unexpected issues, like metadata persisting that you did not expect to.")
426
+ preferred_provider = provider
427
+ end
428
+
429
+ end
430
+ preferred_provider
431
+ end
432
+
433
+ private
434
+
435
+ #
436
+ # @see https://github.com/openhab/openhab-core/issues/3169
437
+ #
438
+ # in the meantime, force the serialization round-trip right now
439
+ #
440
+ def javaify
441
+ mapper = Provider.registry.managed_provider.get.storage.entityMapper
442
+
443
+ @metadata = mapper.from_json(mapper.to_json_tree(@metadata), Metadata.java_class)
444
+ end
386
445
  end
387
446
  end
388
447
  end
@@ -96,12 +96,7 @@ module OpenHAB
96
96
  metadata = Hash.from_item(@item_name, namespace, value)
97
97
  return @hash[metadata.uid.namespace] = metadata unless attached? # rubocop:disable Lint/ReturnInVoidContext
98
98
 
99
- # registry.get can be omitted, but registry.update will log a warning for nonexistent metadata
100
- if self.class.registry.managed_provider.get.get(metadata.uid)
101
- metadata.commit
102
- else
103
- metadata.create
104
- end
99
+ metadata.create_or_update
105
100
  metadata # rubocop:disable Lint/Void
106
101
  end
107
102
  alias_method :store, :[]=
@@ -117,7 +112,11 @@ module OpenHAB
117
112
  # @!visibility private
118
113
  def clear
119
114
  if attached?
120
- self.class.registry.remove_item_metadata(@item_name)
115
+ provider = Provider.current(Thread.current[:openhab_providers]&.dig(:metadata_items, @item_name))
116
+ provider.remove_item_metadata(@item_name)
117
+ Thread.current[:openhab_providers]&.[](:metadata_namespaces)&.each_value do |namespace_provider|
118
+ Provider.current(namespace_provider).remove_item_metadata(@item_name)
119
+ end
121
120
  else
122
121
  @hash.clear
123
122
  end
@@ -171,11 +170,10 @@ module OpenHAB
171
170
 
172
171
  # @!visibility private
173
172
  def delete(namespace, &block)
174
- namespace = namespace.to_s
175
-
176
- return @hash.delete(namespace, &block) unless attached?
173
+ return @hash.delete(namespace.to_s, &block) unless attached?
177
174
 
178
- r = self.class.registry.remove(MetadataKey.new(namespace, @item_name))
175
+ metadata = Hash.from_item(@item_name, namespace, nil)
176
+ r = metadata.remove
179
177
  return yield(namespace) if block && !r
180
178
 
181
179
  Hash.new(r) if r
@@ -208,7 +206,7 @@ module OpenHAB
208
206
  return @hash.each(&block) unless attached?
209
207
  return to_enum(:each) unless block
210
208
 
211
- self.class.registry.all.each do |meta|
209
+ Provider.registry.all.each do |meta|
212
210
  yield meta.uid.namespace, Hash.new(meta) if meta.uid.item_name == @item_name
213
211
  end
214
212
  self
@@ -220,7 +218,7 @@ module OpenHAB
220
218
  return @hash.each_key(&block) unless attached?
221
219
  return to_enum(:each_key) unless block
222
220
 
223
- self.class.registry.all.each do |meta|
221
+ Provider.registry.all.each do |meta|
224
222
  yield meta.uid.namespace if meta.uid.item_name == @item_name
225
223
  end
226
224
  self
@@ -231,7 +229,7 @@ module OpenHAB
231
229
  return @hash.each_value(&block) unless attached?
232
230
  return to_enum(:each_value) unless block_given?
233
231
 
234
- self.class.registry.all.each do |meta|
232
+ Provider.registry.all.each do |meta|
235
233
  yield Hash.new(meta) if meta.uid.item_name == @item_name
236
234
  end
237
235
  self
@@ -241,7 +239,7 @@ module OpenHAB
241
239
  def empty?
242
240
  return @hash.empty? unless attached?
243
241
 
244
- self.class.registry.all.each do |meta|
242
+ Provider.registry.all.each do |meta|
245
243
  return false if meta.uid.item_name == @item_name
246
244
  end
247
245
  true
@@ -263,7 +261,7 @@ module OpenHAB
263
261
  end
264
262
 
265
263
  logger.trace("Getting metadata for item: #{@item_name}, namespace '#{key}'")
266
- if (m = self.class.registry.get(MetadataKey.new(key, @item_name)))
264
+ if (m = Provider.registry.get(MetadataKey.new(key, @item_name)))
267
265
  Hash.new(m)
268
266
  elsif block
269
267
  yield key
@@ -280,7 +278,7 @@ module OpenHAB
280
278
 
281
279
  keys.each_with_object([]) do |key, res|
282
280
  key = key.to_s
283
- if (m = self.class.registry.get(MetadataKey.new(key, @item_name)))
281
+ if (m = Provider.registry.get(MetadataKey.new(key, @item_name)))
284
282
  res << Hash.new(m)
285
283
  elsif block_given?
286
284
  res << yield(key)
@@ -307,7 +305,7 @@ module OpenHAB
307
305
  key = key.to_s
308
306
  return @hash.key?(key) unless attached?
309
307
 
310
- !self.class.registry.get(MetadataKey.new(key, @item_name)).nil?
308
+ !Provider.registry.get(MetadataKey.new(key, @item_name)).nil?
311
309
  end
312
310
  alias_method :has_key?, :key?
313
311
  alias_method :member?, :key?
@@ -373,7 +371,7 @@ module OpenHAB
373
371
 
374
372
  keys = keys.to_set
375
373
  r = {}
376
- self.class.registry.all.each do |meta|
374
+ Provider.registry.all.each do |meta|
377
375
  if meta.uid.item_name == @item_name && keys.include?(meta.uid.namespace)
378
376
  r[meta.uid.namespace] =
379
377
  Hash.new(meta)
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OpenHAB
4
+ module Core
5
+ module Items
6
+ module Metadata
7
+ #
8
+ # Provides metadata created in Ruby to openHAB
9
+ #
10
+ class Provider < Core::Provider
11
+ include org.openhab.core.items.ManagedMetadataProvider
12
+
13
+ class << self
14
+ #
15
+ # The Metadata registry
16
+ #
17
+ # @return [org.openhab.core.items.MetadataRegistry]
18
+ #
19
+ def registry
20
+ @registry ||= OSGi.service("org.openhab.core.items.MetadataRegistry")
21
+ end
22
+ end
23
+
24
+ # see Hash#javaify
25
+ registry.managed_provider.get.class.field_reader :storage
26
+ registry.managed_provider.get.storage.class.field_reader :entityMapper
27
+
28
+ #
29
+ # Removes all metadata of a given item.
30
+ #
31
+ # @param [String] item_name
32
+ # @return [void]
33
+ #
34
+ def remove_item_metadata(item_name)
35
+ @elements.delete_if do |k, v|
36
+ next unless k.item_name == item_name
37
+
38
+ notify_listeners_about_removed_element(v)
39
+ true
40
+ end
41
+ nil
42
+ end
43
+ alias_method :removeItemMetadata, :remove_item_metadata
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OpenHAB
4
+ module Core
5
+ module Items
6
+ #
7
+ # Provides {GenericItem Items} created in Ruby to openHAB
8
+ #
9
+ class Provider < Core::Provider
10
+ include org.openhab.core.items.ItemProvider
11
+
12
+ class << self
13
+ #
14
+ # The Item registry
15
+ #
16
+ # @return [org.openhab.core.items.ItemRegistry]
17
+ #
18
+ def registry
19
+ $ir
20
+ end
21
+ end
22
+
23
+ #
24
+ # Remove an item from this provider
25
+ #
26
+ # @param [String] item_name
27
+ # @param [true, false] recursive
28
+ # @return [GenericItem, nil] The removed item, if found.
29
+ #
30
+ def remove(item_name, recursive = false) # rubocop:disable Style/OptionalBooleanParameter matches Java method
31
+ return nil unless @elements.key?(item_name)
32
+
33
+ item = super(item_name)
34
+ item.members.each { |member| remove(member.name, true) } if recursive && item.is_a?(GroupItem)
35
+ item
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -53,6 +53,16 @@ module OpenHAB
53
53
 
54
54
  super
55
55
  end
56
+
57
+ #
58
+ # Non equality comparison
59
+ #
60
+ # @return [true, false]
61
+ #
62
+ # @!visibility private
63
+ def !=(other)
64
+ !(self == other) # rubocop:disable Style/InverseMethods
65
+ end
56
66
  end
57
67
  end
58
68
  end
@@ -32,6 +32,8 @@ module OpenHAB
32
32
  !$ir.getItems(name).empty?
33
33
  end
34
34
  alias_method :include?, :key?
35
+ # @deprecated
36
+ alias_method :has_key?, :key?
35
37
 
36
38
  # Explicit conversion to array
37
39
  # @return [Array]
@@ -39,26 +41,33 @@ module OpenHAB
39
41
  $ir.items.map { |item| Proxy.new(item) }
40
42
  end
41
43
 
44
+ #
42
45
  # Enter the Item Builder DSL.
46
+ #
47
+ # @param (see Core::Provider.current)
43
48
  # @yield Block executed in the context of a {DSL::Items::Builder}
44
49
  # @return [Object] The return value of the block.
45
- def build(&block)
46
- DSL::Items::BaseBuilderDSL.new.instance_eval(&block)
50
+ #
51
+ def build(preferred_provider = nil, &block)
52
+ DSL::Items::BaseBuilderDSL.new(preferred_provider).instance_eval(&block)
47
53
  end
48
54
 
55
+ #
49
56
  # Remove an item.
50
57
  #
51
- # The item must have either been created by this script, or be a
52
- # managed item (typically created in the UI).
58
+ # The item must be a managed item (typically created by Ruby or in the UI).
53
59
  #
60
+ # @param [String, GenericItem] item_name
54
61
  # @param recursive [true, false] Remove the item's members if it's a group
55
62
  # @return [GenericItem, nil] The removed item, if found.
56
63
  def remove(item_name, recursive: false)
57
64
  item_name = item_name.name if item_name.is_a?(GenericItem)
58
- result = DSL::Items::ItemProvider.instance.remove(item_name, recursive: recursive)
59
- return result if result
65
+ provider = Provider.registry.provider_for(item_name)
66
+ unless provider.is_a?(org.openhab.core.common.registry.ManagedProvider)
67
+ raise "Cannot remove item #{item_name} from non-managed provider #{provider.inspect}"
68
+ end
60
69
 
61
- $ir.remove(item_name, recursive)
70
+ provider.remove(item_name, recursive)
62
71
  end
63
72
  end
64
73
  end
@@ -18,7 +18,7 @@ module OpenHAB
18
18
  #
19
19
  # @!visibility private
20
20
  def self.from_items(*items)
21
- StateStorage.new(org.openhab.core.model.script.actions.BusEvent.store_states(*items).to_h)
21
+ StateStorage.new($events.store_states(*items).to_h)
22
22
  end
23
23
 
24
24
  #
@@ -27,7 +27,7 @@ module OpenHAB
27
27
  # @return [void]
28
28
  #
29
29
  def restore
30
- org.openhab.core.model.script.actions.BusEvent.restore_states(to_h)
30
+ $events.restore_states(to_h)
31
31
  end
32
32
 
33
33
  #
@@ -36,7 +36,7 @@ module OpenHAB
36
36
  # @return [void]
37
37
  #
38
38
  def restore_changes
39
- org.openhab.core.model.script.actions.BusEvent.restore_states(select { |item, value| item.state != value })
39
+ $events.restore_states(select { |item, value| item.state != value })
40
40
  end
41
41
 
42
42
  #
@@ -113,6 +113,6 @@ module OpenHAB
113
113
  end
114
114
 
115
115
  registration = OSGi.register_service(ProfileFactory.instance)
116
- ScriptHandlingCallbacks.script_unloaded_hooks << -> { registration.unregister }
116
+ ScriptHandling.script_unloaded { registration.unregister }
117
117
  end
118
118
  end
@@ -0,0 +1,216 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "singleton"
4
+
5
+ module OpenHAB
6
+ module Core
7
+ # @interface
8
+ java_import org.openhab.core.common.registry.ManagedProvider
9
+
10
+ # @!visibility private
11
+ module ManagedProvider
12
+ # Maps actual element types to the symbol used in Thread.local[:openhab_providers]
13
+ TYPE_TO_PROVIDER_TYPE = {
14
+ org.openhab.core.items.Item.java_class => :items,
15
+ org.openhab.core.items.Metadata.java_class => :metadata,
16
+ org.openhab.core.thing.Thing.java_class => :things,
17
+ org.openhab.core.thing.link.ItemChannelLink.java_class => :links
18
+ }.freeze
19
+ private_constant :TYPE_TO_PROVIDER_TYPE
20
+
21
+ # @return [Symbol, nil]
22
+ def type
23
+ java_class.generic_ancestors.each do |klass|
24
+ next unless klass.respond_to?(:raw_type)
25
+ next unless klass.raw_type == org.openhab.core.common.registry.Provider.java_class
26
+
27
+ type_arg = klass.actual_type_arguments.first
28
+ next unless type_arg.is_a?(java.lang.Class)
29
+ next unless klass.actual_type_arguments.first.is_a?(java.lang.Class)
30
+
31
+ return TYPE_TO_PROVIDER_TYPE[type_arg]
32
+ end
33
+ nil
34
+ end
35
+ end
36
+
37
+ # @abstract
38
+ class Provider < org.openhab.core.common.registry.AbstractProvider
39
+ include org.openhab.core.common.registry.ManagedProvider
40
+ include Singleton
41
+ public_class_method :new
42
+
43
+ # Known supported provider types
44
+ # @return [Array<Symbol>]
45
+ KNOWN_TYPES = %i[items metadata things links].freeze
46
+
47
+ class << self
48
+ #
49
+ # Determines the current provider that should be used to create elements belonging to this registry.
50
+ #
51
+ # @param [org.openhab.core.common.registry.Provider, Proc, :persistent, :transient, nil] preferred_provider
52
+ # An optional preferred provider to use. Can be one of several types:
53
+ # * An explicit instance of {org.openhab.core.common.registry.ManagedProvider ManagedProvider}
54
+ # * A Proc, which can calculate the preferred provider based on whatever conditions it wants,
55
+ # and then is further processed as this parameter.
56
+ # * `:persistent`, meaning the default {org.openhab.core.common.registry.ManagedProvider ManagedProvider}
57
+ # for this registry. Managed providers persist their objects to JSON, and will survive after the
58
+ # Ruby script is unloaded. This is where objects you configure with MainUI are stored. You should
59
+ # use this provider when you're creating something in response to a one-time event.
60
+ # * `:transient`, meaning a {org.openhab.core.common.registry.ManagedProvider ManagedProvider} that
61
+ # will remove all of its contents when the Ruby script is unloaded. You should use this if you're
62
+ # generating objects dynamically, either based on some sort of other configuration, or simply
63
+ # hard coded and you're using Ruby as a more expressive way to define things than a `.items` or
64
+ # `.things` file. If you _don't_ use this provider for something such as metadata, then you
65
+ # may have issues such as metadata still showing up even though you're no longer creating items
66
+ # with it anymore.
67
+ # * `nil`, meaning to fall back to the current thread setting. See {OpenHAB::DSL.provider}.
68
+ # If there is no thread setting (or the thread setting was Proc that returned `nil`),
69
+ # it defaults to `:transient`.
70
+ # @return [org.openhab.core.common.registry.Provider]
71
+ #
72
+ def current(preferred_provider = nil, element = nil)
73
+ preferred_provider ||= Thread.current[:openhab_providers]&.[](type)
74
+ if preferred_provider.is_a?(Proc)
75
+ preferred_provider = if preferred_provider.arity.zero? || element.nil?
76
+ preferred_provider.call
77
+ else
78
+ preferred_provider.call(element)
79
+ end
80
+ end
81
+
82
+ case preferred_provider
83
+ when nil, :transient
84
+ instance
85
+ when :persistent
86
+ registry.managed_provider.get
87
+ when org.openhab.core.common.registry.ManagedProvider
88
+ preferred_provider
89
+ else
90
+ raise ArgumentError, "#{preferred_provider.inspect} is not a ManagedProvider"
91
+ end
92
+ end
93
+
94
+ # @abstract
95
+ # @!attribute [r] registry
96
+ #
97
+ # The registry that this provider provides elements for.
98
+ #
99
+ # @return [org.openhab.core.common.registry.Registry]
100
+ #
101
+ def registry
102
+ raise NotImplementedError
103
+ end
104
+
105
+ #
106
+ # Creates a new instance of a provider, registers it, sets it as the
107
+ # default for the thread, calls the block, and then unregisters it.
108
+ #
109
+ # @param [true, false] thread_provider Set this new provider as the default for the thread
110
+ # @yieldparam [Provider] provider The provider
111
+ # @return [Object] The result of the block
112
+ #
113
+ # @!visibility private
114
+ def new(thread_provider: true)
115
+ unless @singleton__instance__.nil? || block_given?
116
+ raise NoMethodError,
117
+ "private method `new' called for #{self}:Class"
118
+ end
119
+
120
+ r = provider = super()
121
+ if block_given?
122
+ if thread_provider
123
+ DSL.provider(provider) do
124
+ r = yield provider
125
+ end
126
+ else
127
+ r = yield provider
128
+ end
129
+ provider.unregister
130
+ end
131
+ r
132
+ end
133
+
134
+ # @!attribute [r] type
135
+ # @!visibility private
136
+ # @return [Symbol]
137
+ #
138
+ def type
139
+ name.split("::")[-2].downcase.to_sym
140
+ end
141
+ end
142
+
143
+ # @return [String]
144
+ def inspect
145
+ "#<#{self.class.name}:#{object_id}>"
146
+ end
147
+
148
+ # @!visibility private
149
+ def add(element)
150
+ @elements[element.uid] = element
151
+ notify_listeners_about_added_element(element)
152
+ element
153
+ end
154
+
155
+ #
156
+ # Get an element from this provider
157
+ #
158
+ # @param [Object] key The proper key type for the elements in this provider.
159
+ # @return [Object]
160
+ #
161
+ def [](key)
162
+ @elements[key]
163
+ end
164
+ alias_method :get, :[]
165
+
166
+ #
167
+ # Get all elements in this provider
168
+ #
169
+ # @return [Array<Object>]
170
+ #
171
+ def all
172
+ @elements.values
173
+ end
174
+ alias_method :getAll, :all
175
+
176
+ #
177
+ # Remove an element from this provider
178
+ #
179
+ # @return [Object, nil] the removed element
180
+ #
181
+ # @!visibility private
182
+ #
183
+ def remove(key)
184
+ @elements.delete(key)&.tap do |element|
185
+ notify_listeners_about_removed_element(element)
186
+ end
187
+ end
188
+
189
+ # @return [Object, nil] the previous version of the element
190
+ # @!visibility private
191
+ #
192
+ def update(element)
193
+ old_element = @elements[element.uid]
194
+ if old_element
195
+ @elements[element.uid]
196
+ notify_listeners_about_updated_element(old_element, element)
197
+ end
198
+ old_element
199
+ end
200
+
201
+ # @!visibility private
202
+ def unregister
203
+ self.class.registry.remove_provider(self)
204
+ end
205
+
206
+ private
207
+
208
+ def initialize
209
+ super
210
+ @elements = {}
211
+ self.class.registry.add_provider(self)
212
+ ScriptHandling.script_unloaded { unregister }
213
+ end
214
+ end
215
+ end
216
+ end