openhab-scripting 5.43.0 → 5.44.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6b42fbceb3c29151aaef433d5992fa21dd38662e25e3644cdbdc0a81cfa392d5
4
- data.tar.gz: 7ce847854bad3ccc7b2734cbd788b5a1a3fe21e82ec966240554a645a19b3518
3
+ metadata.gz: 14e2d94024913efabc184b537c27841fcba1136785987bd7b1423e0cde7fc072
4
+ data.tar.gz: c6e1746a22bba5b3e78f3f4e32dd2a5f09fdef208b098fe08558c13ff03d34e3
5
5
  SHA512:
6
- metadata.gz: 8f0940e4520b47a7f35dada758fea1e079d8fca10e9e484e4d54f2cea738b7ca6d06dd81eed936c1525b5f9ef9fb884d4fb36fd4e714adc47c8d87544a824368
7
- data.tar.gz: edba4793deda5989f59b0b8c106273d3ffb3963575c8dbcbeb45d75e316141cba86528c8e6126c4e53629043be86d21a6b321c174a2ec90803eec22217853634
6
+ metadata.gz: 41eb14f924ddfb42ea4add71eec184f0c1478b82fd129caf63bade3098e868ff78c432a7b4390ecc105b0bc22745da415b848d2f4f2b44decfffec7f8aecbf37
7
+ data.tar.gz: ee38fa1780d063681b6c710f4aee272ef0de6cb356a18acbe603d1e666596ffc74572d7da698084aaf6849f94b2b62396d5b4d255493b38a3ad3c9109b550af7
@@ -34,7 +34,20 @@ module OpenHAB
34
34
  end
35
35
 
36
36
  # @!attribute [r] source
37
- # @return [String] The component that sent the event.
37
+ # @return [Source, nil] The component(s) that sent the event.
38
+ def source
39
+ unless instance_variable_defined?(:@source)
40
+ begin
41
+ # Disable "instance vars on non-persistent Java type"
42
+ original_verbose = $VERBOSE
43
+ $VERBOSE = nil
44
+ @source = get_source && Source.new(get_source)
45
+ ensure
46
+ $VERBOSE = original_verbose
47
+ end
48
+ end
49
+ @source
50
+ end
38
51
 
39
52
  #
40
53
  # Returns the event payload as a Hash.
@@ -0,0 +1,308 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "delegate"
4
+
5
+ module OpenHAB
6
+ module Core
7
+ module Events
8
+ #
9
+ # Represents the source of an event as a chain of delegated {Component Components}.
10
+ #
11
+ # This class behaves like a String representing the event source, but also provides
12
+ # methods to access the individual components in the delegation chain.
13
+ #
14
+ # Starting from openHAB 5.1, the source can contain multiple components
15
+ # that contain information about the delegation chain of the event.
16
+ #
17
+ # Each {Source::Component component} contains:
18
+ # - {Source::Component#bundle bundle}: The module or app.
19
+ # For example: `org.openhab.automation.jrubyscripting` when a rule sends a command,
20
+ # or `org.openhab.core.io.rest` when a command comes from the REST API (UI).
21
+ # - {Source::Component#actor actor}: Optional. The rule, user or thinguid
22
+ # (e.g., "lighting_rule", "mqtt:topic:livingroom-switch:switch4")
23
+ #
24
+ # @example Log commands with source information
25
+ # rule "Log item commands" do
26
+ # received_command MyItem
27
+ # run do |event|
28
+ # logger.info "#{MyItem.name} received command #{event.command} from: #{event.source}"
29
+ # logger.info " Source components:"
30
+ # event.source.components.each_with_index do |component, index|
31
+ # logger.info " #{index}: bundle=#{component.bundle}, actor=#{component.actor}"
32
+ # end
33
+ # end
34
+ # end
35
+ #
36
+ # @example Ignore commands from specific integrations
37
+ # rule "Ignore UI commands" do
38
+ # received_command MyItem
39
+ # run do |event|
40
+ # next if event.source.sender?("org.openhab.core.io.rest")
41
+ # # process the command
42
+ # end
43
+ # end
44
+ #
45
+ # @see https://www.openhab.org/docs/developer/utils/events.html#the-core-events
46
+ # @see AbstractEvent#source
47
+ # @see OpenHAB::DSL.profile
48
+ #
49
+ class Source < Delegator
50
+ # The components in the event source delegation chain.
51
+ # @return [Array<Component>]
52
+ attr_reader :components
53
+
54
+ #
55
+ # Construct a new {Source} object.
56
+ #
57
+ # @overload initialize(source)
58
+ # @param [String] source The event source as a string.
59
+ #
60
+ # @overload initialize(components)
61
+ # @param [Array<Component>] components The components in the event source delegation chain.
62
+ #
63
+ def initialize(source_or_components) # rubocop:disable Lint/MissingSuper
64
+ @components = if source_or_components.is_a?(Array)
65
+ @source = nil
66
+ source_or_components.dup
67
+ else
68
+ @source = -source_or_components
69
+ @source.split("=>").map { |s| Component.parse(s) }
70
+ end.freeze
71
+ end
72
+
73
+ #
74
+ # Construct a new {Source} by adding an additional component to the delegation chain.
75
+ #
76
+ # @param [String] bundle The bundle (module, app, etc.) of the new component to add to the chain.
77
+ # @param [String, nil] actor The actor (user, device, etc.) of the new component to add to the chain.
78
+ # @return [Source]
79
+ #
80
+ def delegate(bundle, actor = nil)
81
+ Source.new(components + [Component.build(bundle, actor)])
82
+ end
83
+
84
+ #
85
+ # Check if the event was sent by the specified bundle or actor.
86
+ #
87
+ # Checks if any component matches the specified bundle or actor.
88
+ #
89
+ # @overload sender?(bundle_or_actor)
90
+ # @param [#===] bundle_or_actor
91
+ # The bundle (module, app, etc.) or actor (user, device, etc.) to check.
92
+ # If either a bundle or actor in any component in the source matches, this method returns true.
93
+ # @return [true, false]
94
+ #
95
+ # @overload sender?(bundle: nil, actor: nil)
96
+ # @param [#===] bundle
97
+ # @param [#===] actor
98
+ # @return [true, false]
99
+ #
100
+ def sender?(bundle_or_actor = nil, bundle: nil, actor: nil)
101
+ unless bundle_or_actor || bundle || actor
102
+ raise ArgumentError, "Specify one of bundle_or_actor, bundle or actor"
103
+ end
104
+
105
+ # rubocop:disable Style/CaseEquality
106
+ components.any? do |sender|
107
+ (bundle && bundle === sender.bundle) ||
108
+ (actor && actor === sender.actor) ||
109
+ (bundle_or_actor && bundle_or_actor === sender.bundle) ||
110
+ (bundle_or_actor && bundle_or_actor === sender.actor)
111
+ end
112
+ # rubocop:enable Style/CaseEquality
113
+ end
114
+
115
+ #
116
+ # @param [#===] bundle The bundle (module, app, etc.) to find the actor for.
117
+ # @return [String, nil] the actor (user, device, etc.) for the specified bundle, if any.
118
+ #
119
+ def actor_for(bundle)
120
+ components.find { |c| bundle === c.bundle }&.actor # rubocop:disable Style/CaseEquality
121
+ end
122
+
123
+ #
124
+ # Construct a new {Source} without any components from the specified bundle.
125
+ #
126
+ # This is useful if you consider events from a specific bundle as sensitive,
127
+ # and want to filter that component out from an untrusted sender.
128
+ #
129
+ # @overload reject(bundle)
130
+ # @param [#===] bundle The bundle (module, app, etc.) to reject.
131
+ # @return [Source] a new Source without any components from the specified bundle.
132
+ #
133
+ # @overload reject { |component| ... }
134
+ # @yieldparam [Component] component Each component in the delegation chain.
135
+ # @return [Source] a new Source without any components for which the block returns true.
136
+ #
137
+ def reject(bundle = nil, &)
138
+ raise ArgumentError, "Either a bundle or a block must be given" unless bundle || block_given?
139
+
140
+ Source.new(if block_given?
141
+ components.reject(&)
142
+ else
143
+ components.reject { |c| bundle === c.bundle } # rubocop:disable Style/CaseEquality
144
+ end)
145
+ end
146
+
147
+ # @attribute [r] source
148
+ #
149
+ # The event source as a string.
150
+ #
151
+ # @return [String]
152
+ #
153
+ def source
154
+ @source ||= components.join("=>").freeze
155
+ end
156
+
157
+ # @attribute [r] bundle
158
+ #
159
+ # The bundle (module, app, etc.) of the initial component that sent the event.
160
+ #
161
+ # @return [String, nil]
162
+ #
163
+ def bundle
164
+ components.first&.bundle
165
+ end
166
+
167
+ # @attribute [r] actor
168
+ #
169
+ # The actor (user, device, etc.) of the initial component that sent the event.
170
+ #
171
+ # @return [String, nil]
172
+ #
173
+ def actor
174
+ components.first&.actor
175
+ end
176
+
177
+ alias_method :to_s, :source
178
+ alias_method :to_str, :source
179
+ alias_method :inspect, :source
180
+ alias_method :__getobj__, :source
181
+
182
+ # @return [true, false]
183
+ def ==(other)
184
+ return components == other.components if other.is_a?(Source)
185
+ return to_s == other.to_str if other.respond_to?(:to_str)
186
+
187
+ false
188
+ end
189
+
190
+ # @return [true, false]
191
+ def !=(other)
192
+ !(self == other) # rubocop:disable Style/InverseMethods
193
+ end
194
+
195
+ # @return [Integer, nil]
196
+ def <=>(other)
197
+ return 0 if self == other
198
+ return nil unless other.respond_to?(:to_str)
199
+
200
+ to_s <=> other.to_str
201
+ end
202
+
203
+ def eql?(other)
204
+ other.is_a?(Source) && components == other.components
205
+ end
206
+
207
+ # @return [Integer]
208
+ def hash
209
+ components.hash
210
+ end
211
+
212
+ # Represents a single component in the event source delegation chain.
213
+ class Component
214
+ include Comparable
215
+
216
+ # The bundle (module, app, etc.) that sent the event.
217
+ # @return [String]
218
+ attr_reader :bundle
219
+
220
+ # The actor (user, device, etc.) that sent the event.
221
+ # @return [String]
222
+ attr_reader :actor
223
+
224
+ class << self
225
+ #
226
+ # Parse a {Component} from its string representation.
227
+ #
228
+ # @param [String] component The string representation of the {Component}.
229
+ # @return [Component]
230
+ #
231
+ def parse(component)
232
+ new(*component.split("$", 2))
233
+ end
234
+
235
+ #
236
+ # Build a {Component} from the specified bundle and actor.
237
+ #
238
+ # @param [String] bundle The bundle (module, app, etc.) that sent the event.
239
+ # @param [String, nil] actor The actor (user, device, etc.) that sent the event.
240
+ # @return [Component]
241
+ #
242
+ def build(bundle, actor = nil)
243
+ if AbstractEvent.respond_to?(:build_source)
244
+ # a bit round-about, but is necessary for argument validation
245
+ # and escaping
246
+ # Only present in openHAB 5.1+
247
+ begin
248
+ parse(AbstractEvent.build_source(bundle, actor))
249
+ rescue java.lang.IllegalArgumentException => e
250
+ raise ArgumentError, e.message
251
+ end
252
+ else
253
+ new(bundle, actor)
254
+ end
255
+ end
256
+ end
257
+
258
+ # @return [String]
259
+ def to_s
260
+ if actor
261
+ "#{bundle}$#{actor}"
262
+ else
263
+ bundle
264
+ end
265
+ end
266
+ alias_method :to_str, :to_s
267
+
268
+ # @return [true, false]
269
+ def ==(other)
270
+ return bundle == other.bundle && actor == other.actor if other.is_a?(Component)
271
+ return to_s == other.to_str if other.respond_to?(:to_str)
272
+
273
+ false
274
+ end
275
+
276
+ # @return [true, false]
277
+ def !=(other)
278
+ !(self == other) # rubocop:disable Style/InverseMethods
279
+ end
280
+
281
+ # @return [Integer, nil]
282
+ def <=>(other)
283
+ return 0 if self == other
284
+ return nil unless other.respond_to?(:to_str)
285
+
286
+ to_s <=> other.to_str
287
+ end
288
+
289
+ def eql?(other)
290
+ other.is_a?(Component) && bundle == other.bundle && actor == other.actor
291
+ end
292
+
293
+ # @return [Integer]
294
+ def hash
295
+ [bundle, actor].hash
296
+ end
297
+
298
+ private
299
+
300
+ def initialize(bundle, actor = nil)
301
+ @bundle = bundle
302
+ @actor = actor
303
+ end
304
+ end
305
+ end
306
+ end
307
+ end
308
+ end
@@ -92,7 +92,7 @@ module OpenHAB
92
92
  params[:command] ||= nil
93
93
  params[:trigger] ||= nil
94
94
  params[:time_series] ||= nil
95
- params[:source] ||= nil
95
+ params[:source] = (params[:source] && Core::Events::Source.new(params[:source])) || nil
96
96
 
97
97
  kwargs = {}
98
98
  @block.parameters.each do |(param_type, name)|
@@ -4,6 +4,6 @@ module OpenHAB
4
4
  module DSL
5
5
  # Version of openHAB helper libraries
6
6
  # @return [String]
7
- VERSION = "5.43.0"
7
+ VERSION = "5.44.0"
8
8
  end
9
9
  end
data/lib/openhab/dsl.rb CHANGED
@@ -158,7 +158,7 @@ module OpenHAB
158
158
  # @yieldparam [Core::Things::ChannelUID] channel_uid The linked channel.
159
159
  # @yieldparam [Hash] configuration The profile configuration.
160
160
  # @yieldparam [org.openhab.core.thing.profiles.ProfileContext] context The profile context.
161
- # @yieldparam [String, nil] source The source of the event.
161
+ # @yieldparam [Core::Events::Source, nil] source The source of the event.
162
162
  # @since openHAB 5.1
163
163
  # @yieldreturn [Boolean] Return true from the block in order to have default processing.
164
164
  # @return [void]
@@ -109,10 +109,6 @@ module OpenHAB
109
109
  end
110
110
  end
111
111
 
112
- def get_default_strategies # rubocop:disable Naming/AccessorMethodName -- must match Java interface
113
- [org.openhab.core.persistence.strategy.PersistenceStrategy::Globals::CHANGE]
114
- end
115
-
116
112
  private
117
113
 
118
114
  def query_internal(filter, &)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: openhab-scripting
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.43.0
4
+ version: 5.44.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brian O'Connell
@@ -96,6 +96,7 @@ files:
96
96
  - lib/openhab/core/events/item_state_event.rb
97
97
  - lib/openhab/core/events/item_state_updated_event.rb
98
98
  - lib/openhab/core/events/item_time_series_updated_event.rb
99
+ - lib/openhab/core/events/source.rb
99
100
  - lib/openhab/core/events/startlevel_event.rb
100
101
  - lib/openhab/core/events/thing_status_info_event.rb
101
102
  - lib/openhab/core/events/timer_event.rb