openhab-scripting 5.35.1 → 5.36.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.
Files changed (94) hide show
  1. checksums.yaml +4 -4
  2. data/lib/openhab/console/irb.rb +105 -0
  3. data/lib/openhab/console/jline.rb +104 -0
  4. data/lib/openhab/console/registry.rb +12 -0
  5. data/lib/openhab/console/stdio.rb +178 -0
  6. data/lib/openhab/console.rb +5 -0
  7. data/lib/openhab/core/emulate_hash.rb +11 -11
  8. data/lib/openhab/core/entity_lookup.rb +2 -4
  9. data/lib/openhab/core/events/item_state_updated_event.rb +0 -3
  10. data/lib/openhab/core/events/item_time_series_updated_event.rb +0 -3
  11. data/lib/openhab/core/events/startlevel_event.rb +0 -3
  12. data/lib/openhab/core/events/timer_event.rb +0 -3
  13. data/lib/openhab/core/items/generic_item.rb +14 -154
  14. data/lib/openhab/core/items/group_item.rb +2 -2
  15. data/lib/openhab/core/items/image_item.rb +5 -21
  16. data/lib/openhab/core/items/item.rb +161 -7
  17. data/lib/openhab/core/items/persistence.rb +8 -10
  18. data/lib/openhab/core/items/provider.rb +1 -1
  19. data/lib/openhab/core/items/proxy.rb +33 -94
  20. data/lib/openhab/core/items/registry.rb +1 -1
  21. data/lib/openhab/core/items/semantics/enumerable.rb +1 -1
  22. data/lib/openhab/core/items/semantics/provider.rb +1 -5
  23. data/lib/openhab/core/items/semantics/semantic_tag.rb +0 -3
  24. data/lib/openhab/core/items/semantics.rb +105 -141
  25. data/lib/openhab/core/items/switch_item.rb +1 -1
  26. data/lib/openhab/core/items.rb +22 -22
  27. data/lib/openhab/core/lazy_array.rb +4 -4
  28. data/lib/openhab/core/profile_factory.rb +16 -25
  29. data/lib/openhab/core/provider.rb +3 -4
  30. data/lib/openhab/core/proxy.rb +160 -4
  31. data/lib/openhab/core/rules/registry.rb +2 -2
  32. data/lib/openhab/core/rules/rule.rb +4 -8
  33. data/lib/openhab/core/script_handling.rb +2 -2
  34. data/lib/openhab/core/sitemaps/provider.rb +1 -1
  35. data/lib/openhab/core/things/channel.rb +0 -28
  36. data/lib/openhab/core/things/profile_callback.rb +3 -3
  37. data/lib/openhab/core/things/proxy.rb +8 -51
  38. data/lib/openhab/core/things/registry.rb +1 -1
  39. data/lib/openhab/core/things/thing.rb +3 -5
  40. data/lib/openhab/core/types/command_description.rb +31 -0
  41. data/lib/openhab/core/types/date_time_type.rb +5 -10
  42. data/lib/openhab/core/types/decimal_type.rb +1 -1
  43. data/lib/openhab/core/types/hsb_type.rb +3 -5
  44. data/lib/openhab/core/types/point_type.rb +1 -1
  45. data/lib/openhab/core/types/quantity_type.rb +22 -2
  46. data/lib/openhab/core/types/raw_type.rb +10 -4
  47. data/lib/openhab/core/types/state_description.rb +54 -0
  48. data/lib/openhab/core/types/time_series.rb +0 -3
  49. data/lib/openhab/core/types.rb +2 -2
  50. data/lib/openhab/core/value_cache.rb +3 -3
  51. data/lib/openhab/core.rb +3 -5
  52. data/lib/openhab/core_ext/java/duration.rb +27 -8
  53. data/lib/openhab/core_ext/java/list.rb +1 -1
  54. data/lib/openhab/core_ext/java/local_date.rb +6 -2
  55. data/lib/openhab/core_ext/java/local_time.rb +4 -2
  56. data/lib/openhab/core_ext/java/map.rb +2 -2
  57. data/lib/openhab/core_ext/java/period.rb +9 -6
  58. data/lib/openhab/core_ext/java/temporal_amount.rb +5 -0
  59. data/lib/openhab/core_ext/java/zoned_date_time.rb +12 -6
  60. data/lib/openhab/core_ext/ruby/date.rb +8 -7
  61. data/lib/openhab/core_ext/ruby/date_time.rb +2 -2
  62. data/lib/openhab/core_ext/ruby/time.rb +2 -2
  63. data/lib/openhab/core_ext.rb +1 -1
  64. data/lib/openhab/dsl/config_description/builder.rb +1 -1
  65. data/lib/openhab/dsl/items/builder.rb +5 -13
  66. data/lib/openhab/dsl/items/ensure.rb +3 -5
  67. data/lib/openhab/dsl/items/timed_command.rb +4 -4
  68. data/lib/openhab/dsl/rules/automation_rule.rb +3 -3
  69. data/lib/openhab/dsl/rules/builder.rb +40 -52
  70. data/lib/openhab/dsl/rules/rule_triggers.rb +1 -1
  71. data/lib/openhab/dsl/rules/triggers/changed.rb +16 -15
  72. data/lib/openhab/dsl/rules/triggers/channel.rb +1 -1
  73. data/lib/openhab/dsl/rules/triggers/command.rb +2 -2
  74. data/lib/openhab/dsl/rules/triggers/conditions/duration.rb +4 -4
  75. data/lib/openhab/dsl/rules/triggers/cron/cron.rb +4 -14
  76. data/lib/openhab/dsl/rules/triggers/updated.rb +6 -6
  77. data/lib/openhab/dsl/rules/triggers/watch/watch_handler.rb +69 -124
  78. data/lib/openhab/dsl/sitemaps/builder.rb +7 -17
  79. data/lib/openhab/dsl/things/builder.rb +8 -8
  80. data/lib/openhab/dsl/timer_manager.rb +2 -2
  81. data/lib/openhab/dsl/version.rb +1 -1
  82. data/lib/openhab/dsl.rb +14 -15
  83. data/lib/openhab/log.rb +3 -3
  84. data/lib/openhab/osgi.rb +1 -1
  85. data/lib/openhab/rspec/helpers.rb +3 -3
  86. data/lib/openhab/rspec/hooks.rb +2 -8
  87. data/lib/openhab/rspec/jruby.rb +1 -1
  88. data/lib/openhab/rspec/karaf.rb +5 -27
  89. data/lib/openhab/rspec/mocks/persistence_service.rb +5 -5
  90. data/lib/openhab/yard/html_helper.rb +1 -1
  91. data/lib/openhab/yard.rb +1 -1
  92. metadata +18 -13
  93. data/lib/openhab/core/items/semantics/tag_class_methods.rb +0 -73
  94. data/lib/openhab/dsl/rules/triggers/cron/cron_handler.rb +0 -118
@@ -12,10 +12,8 @@ module OpenHAB
12
12
  # {HSBType} is a complex type with constituents for hue, saturation and
13
13
  # brightness and can be used for color items.
14
14
  class HSBType < PercentType
15
- if OpenHAB::Core.version >= OpenHAB::Core::V4_0
16
- java_import org.openhab.core.util.ColorUtil
17
- private_constant :ColorUtil
18
- end
15
+ java_import org.openhab.core.util.ColorUtil
16
+ private_constant :ColorUtil
19
17
 
20
18
  # @!constant BLACK
21
19
  # @return [HSBType]
@@ -99,7 +97,7 @@ module OpenHAB
99
97
  end
100
98
  end
101
99
 
102
- super(*args)
100
+ super
103
101
  end
104
102
 
105
103
  # Create HSBType from a color temperature
@@ -31,7 +31,7 @@ module OpenHAB
31
31
  end
32
32
  end
33
33
 
34
- super(*args)
34
+ super
35
35
  end
36
36
 
37
37
  #
@@ -189,7 +189,7 @@ module OpenHAB
189
189
  }.each do |java_op, ruby_op|
190
190
  convert = "self.class.new(other, thread_unit)"
191
191
 
192
- class_eval( # rubocop:disable Style/DocumentDynamicEvalDefinition https://github.com/rubocop/rubocop/issues/10179
192
+ class_eval( # rubocop:disable Style/DocumentDynamicEvalDefinition -- https://github.com/rubocop/rubocop/issues/10179
193
193
  # def +(other)
194
194
  # logger.trace { "#{self} + #{other} (#{other.class})" }
195
195
  # other = other.state if other.is_a?(Core::Items::Persistence::PersistedState)
@@ -209,6 +209,9 @@ module OpenHAB
209
209
  # else
210
210
  # raise TypeError, "#{other.class} can't be coerced into #{self.class}"
211
211
  # end
212
+ # elsif !other.is_a?(Numeric) && !other.is_a?(java.lang.Number) &&
213
+ # other.respond_to?(:coerce) && (lhs, rhs = other.coerce(self))
214
+ # return lhs + rhs
212
215
  # else
213
216
  # raise TypeError,
214
217
  # "#{self.class} can only be added with another #{self.class} outside a unit block"
@@ -234,6 +237,9 @@ module OpenHAB
234
237
  else
235
238
  raise TypeError, "\#{other.class} can't be coerced into \#{self.class}"
236
239
  end
240
+ elsif !other.is_a?(Numeric) && !other.is_a?(java.lang.Number) &&
241
+ other.respond_to?(:coerce) && (lhs, rhs = other.coerce(self))
242
+ return lhs #{ruby_op} rhs
237
243
  else
238
244
  raise TypeError,
239
245
  "\#{self.class} can only be #{java_op}ed with another \#{self.class} outside a unit block"
@@ -247,7 +253,7 @@ module OpenHAB
247
253
  multiply: :*,
248
254
  divide: :/
249
255
  }.each do |java_op, ruby_op|
250
- class_eval( # rubocop:disable Style/DocumentDynamicEvalDefinition https://github.com/rubocop/rubocop/issues/10179
256
+ class_eval( # rubocop:disable Style/DocumentDynamicEvalDefinition -- https://github.com/rubocop/rubocop/issues/10179
251
257
  # def *(other)
252
258
  # logger.trace { "#{self} * #{other} (#{other.class})" }
253
259
  # other = other.state if other.is_a?(Core::Items::Persistence::PersistedState)
@@ -287,6 +293,20 @@ module OpenHAB
287
293
  )
288
294
  end
289
295
 
296
+ #
297
+ # Convert this {QuantityType} into a {Duration} if the unit is time-based.
298
+ #
299
+ # @return [Duration] a {Duration} if the unit is time-based
300
+ # @raise [TypeError] if the unit is not time-based
301
+ #
302
+ # @see CoreExt::Java::TemporalAmount#to_temporal_amount
303
+ #
304
+ def to_temporal_amount
305
+ return Duration.of_nanos(to_unit("ns").to_i) if unit.compatible?(Units::SECOND)
306
+
307
+ raise TypeError, "#{self} is not a time-based Quantity"
308
+ end
309
+
290
310
  # if it's a dimensionless quantity, change the unit to match other_unit
291
311
  # @!visibility private
292
312
  def unitize(other_unit = unit, relative: false)
@@ -10,14 +10,20 @@ module OpenHAB
10
10
  #
11
11
  # This type can be used for all binary data such as images, documents, sounds etc.
12
12
  #
13
- class RawType # rubocop:disable Lint/EmptyClass
13
+ class RawType
14
14
  # @!parse include State
15
15
 
16
- # @!method mime_type
16
+ # @attribute [r] mime_type
17
17
  # @return [String]
18
18
 
19
- # @!method bytes
20
- # @return [String]
19
+ # @attribute[r] bytes
20
+ # @return [byte[]]
21
+
22
+ # @attribute [r] bytesize
23
+ # @return [Integer]
24
+ def bytesize
25
+ bytes.size
26
+ end
21
27
  end
22
28
  end
23
29
  end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OpenHAB
4
+ module Core
5
+ module Types
6
+ StateDescription = org.openhab.core.types.StateDescription
7
+
8
+ # Describes restrictions of an item state and gives information how to interpret it
9
+ class StateDescription
10
+ # @!attribute [r] step
11
+ # @return [BigDecimal, nil]
12
+
13
+ # @!attribute [r] pattern
14
+ # @return [String, nil]
15
+
16
+ # @!attribute [r] read_only?
17
+ # @return [true, false]
18
+
19
+ # @!attribute [r] options
20
+ # @return [Array<org.openhab.core.types.StateOption>]
21
+
22
+ # @!attribute [r] range
23
+ # @return [Range, nil]
24
+ def range
25
+ return nil unless minimum || maximum
26
+
27
+ minimum..maximum
28
+ end
29
+
30
+ # @return [String]
31
+ def inspect
32
+ s = "#<OpenHAB::Core::Types::StateDescription"
33
+ r = range
34
+ s += " read_only" if read_only?
35
+ s += " range=#{r}" if r
36
+ s += " step=#{step}" if step
37
+ s += " pattern=#{pattern.inspect}" if pattern && !pattern.empty?
38
+ unless options.empty?
39
+ s += " options=["
40
+ options.each_with_index do |o, i|
41
+ s += ", " if i != 0
42
+
43
+ s += o.value.inspect
44
+
45
+ s += " (#{o.label.inspect})" if o.value != o.label && !o.label.nil?
46
+ end
47
+ s += "]"
48
+ end
49
+ "#{s}>"
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -1,8 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # @deprecated OH4.0 this guard is not needed on OH4.1
4
- return unless OpenHAB::Core.version >= OpenHAB::Core::V4_1
5
-
6
3
  require "forwardable"
7
4
  require "openhab/core/lazy_array"
8
5
 
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- Dir[File.expand_path("types/*.rb", __dir__)].sort.each do |f|
3
+ Dir[File.expand_path("types/*.rb", __dir__)].each do |f|
4
4
  require f
5
5
  end
6
6
 
@@ -47,7 +47,7 @@ module OpenHAB
47
47
  klass.remove_method(:==)
48
48
 
49
49
  # dynamically define predicate methods
50
- klass.values.each do |value| # rubocop:disable Style/HashEachMethods this isn't a Ruby hash
50
+ klass.values.each do |value| # rubocop:disable Style/HashEachMethods -- this isn't a Ruby hash
51
51
  # include all the aliases that we define for items both command and
52
52
  # state aliases (since types can be interrogated as an incoming
53
53
  # command, or as the state of an item)
@@ -57,8 +57,8 @@ module OpenHAB
57
57
  # @yieldreturn [Object] new value
58
58
  # @return [Object] new value or current value
59
59
  #
60
- def compute_if_absent(key, &block)
61
- get(key.to_s, &block)
60
+ def compute_if_absent(key, &)
61
+ get(key.to_s, &)
62
62
  end
63
63
 
64
64
  # @see https://docs.ruby-lang.org/en/master/Hash.html#method-i-5B-5D-3D Hash#[]=
@@ -97,7 +97,7 @@ module OpenHAB
97
97
  end
98
98
  else
99
99
  get(key) do
100
- raise KeyError.new("key not found: #{key.inspect}", key: key)
100
+ raise KeyError.new("key not found: #{key.inspect}", key:)
101
101
  end
102
102
  end
103
103
  else
data/lib/openhab/core.rb CHANGED
@@ -3,12 +3,10 @@
3
3
  module OpenHAB
4
4
  # Contains classes and modules that wrap actual openHAB objects
5
5
  module Core
6
- # The openHAB Version. >= 3.4.0 is required.
6
+ # The openHAB Version. >= 4.1 is required.
7
7
  # @return [String]
8
8
  VERSION = org.openhab.core.OpenHAB.version.freeze
9
9
 
10
- # @!visibility private
11
- V4_0 = Gem::Version.new("4.0.0").freeze
12
10
  # @!visibility private
13
11
  V4_1 = Gem::Version.new("4.1.0").freeze
14
12
  # @!visibility private
@@ -23,7 +21,7 @@ module OpenHAB
23
21
  @version ||= Gem::Version.new(VERSION).release.freeze
24
22
  end
25
23
 
26
- raise "`openhab-scripting` requires openHAB >= 3.4.0" unless version >= Gem::Version.new("3.4.0")
24
+ raise "`openhab-scripting` requires openHAB >= 4.1.0" unless version >= V4_1
27
25
 
28
26
  # @return [Integer] Number of seconds to wait between checks for automation manager
29
27
  CHECK_DELAY = 10
@@ -133,6 +131,6 @@ end
133
131
  # several classes rely on this, so force it to load earlier
134
132
  require_relative "core/provider"
135
133
 
136
- Dir[File.expand_path("core/**/*.rb", __dir__)].sort.each do |f|
134
+ Dir[File.expand_path("core/**/*.rb", __dir__)].each do |f|
137
135
  require f
138
136
  end
@@ -55,11 +55,24 @@ module OpenHAB
55
55
 
56
56
  remove_method :==
57
57
 
58
- # @return [Integer, nil]
58
+ #
59
+ # Comparisons against other types may be done if supported by that type's coercion.
60
+ #
61
+ # @return [Numeric, QuantityType, nil]
62
+ #
59
63
  def <=>(other)
60
- return to_f <=> other if other.is_a?(Numeric)
61
-
62
- super
64
+ logger.trace { "(#{self.class}) #{self} <=> #{other} (#{other.class})" }
65
+ case other
66
+ when Duration then super
67
+ when Numeric then to_f <=> other
68
+ when QuantityType then self <=> other.to_temporal_amount
69
+ else
70
+ if other.respond_to?(:coerce) && (lhs, rhs = other.coerce(self))
71
+ lhs <=> rhs
72
+ else
73
+ super
74
+ end
75
+ end
63
76
  rescue TypeError
64
77
  nil
65
78
  end
@@ -72,6 +85,8 @@ module OpenHAB
72
85
  #
73
86
  def coerce(other)
74
87
  return [other.seconds, self] if other.is_a?(Numeric)
88
+ # We want to return the same type as other, e.g. QuantityType + Duration = QuantityType
89
+ return [other, to_nanos | "ns"] if other.is_a?(QuantityType) && other.unit.compatible?(Units::SECOND)
75
90
 
76
91
  [other.to_i.seconds, self] if other.is_a?(Period)
77
92
  end
@@ -87,7 +102,9 @@ module OpenHAB
87
102
  # plus_seconds(other)
88
103
  # elsif other.is_a?(Numeric)
89
104
  # plus(other.seconds)
90
- # elsif other.respond_to?(:coerce) && (rhs, lhs = other.coerce(self))
105
+ # elsif other.is_a?(QuantityType)
106
+ # plus(other.to_temporal_amount)
107
+ # elsif other.respond_to?(:coerce) && (lhs, rhs = other.coerce(self))
91
108
  # lhs + rhs
92
109
  # else
93
110
  # raise TypeError, "#{other.class} can't be coerced into Duration"
@@ -101,7 +118,9 @@ module OpenHAB
101
118
  #{java_op}_seconds(other)
102
119
  elsif other.is_a?(Numeric)
103
120
  #{java_op}(other.seconds)
104
- elsif other.respond_to?(:coerce) && (rhs, lhs = other.coerce(self))
121
+ elsif other.is_a?(QuantityType)
122
+ #{java_op}(other.to_temporal_amount)
123
+ elsif other.respond_to?(:coerce) && (lhs, rhs = other.coerce(self))
105
124
  lhs #{ruby_op} rhs
106
125
  else
107
126
  raise TypeError, "\#{other.class} can't be coerced into Duration"
@@ -121,7 +140,7 @@ module OpenHAB
121
140
  # Duration.of_seconds(to_f * other)
122
141
  # elsif other.is_a?(Duration)
123
142
  # Duration.of_seconds(to_f * other.to_f)
124
- # elsif other.respond_to?(:coerce) && (rhs, lhs = other.coerce(self))
143
+ # elsif other.respond_to?(:coerce) && (lhs, rhs = other.coerce(self))
125
144
  # lhs * rhs
126
145
  # else
127
146
  # raise TypeError, "#{other.class} can't be coerced into Duration"
@@ -135,7 +154,7 @@ module OpenHAB
135
154
  Duration.of_seconds(to_f #{ruby_op} other)
136
155
  elsif other.is_a?(Duration)
137
156
  Duration.of_seconds(to_f #{ruby_op} other.to_f)
138
- elsif other.respond_to?(:coerce) && (rhs, lhs = other.coerce(self))
157
+ elsif other.respond_to?(:coerce) && (lhs, rhs = other.coerce(self))
139
158
  lhs #{ruby_op} rhs
140
159
  else
141
160
  raise TypeError, "\#{other.class} can't be coerced into Duration"
@@ -217,7 +217,7 @@ module Java::JavaUtil::List # rubocop:disable Style/ClassAndModuleChildren
217
217
  end
218
218
 
219
219
  def intersect?(other_ary)
220
- !(self & other_ary).empty?
220
+ !(self & other_ary).empty? # rubocop:disable Style/ArrayIntersect
221
221
  end
222
222
 
223
223
  def keep_if?
@@ -26,7 +26,7 @@ module OpenHAB
26
26
 
27
27
  # @!scope instance
28
28
 
29
- # @param [TemporalAmount, LocalDate, Numeric] other
29
+ # @param [TemporalAmount, LocalDate, Numeric, QuantityType] other
30
30
  # If other is a Numeric, it's interpreted as days.
31
31
  # @return [LocalDate] If other is a TemporalAmount or Numeric
32
32
  # @return [Period] If other is a LocalDate
@@ -42,12 +42,14 @@ module OpenHAB
42
42
  minus_days(other.to_days)
43
43
  when Numeric
44
44
  minus_days(other.ceil)
45
+ when QuantityType
46
+ minus_days(other.to_temporal_amount.to_days)
45
47
  else
46
48
  minus(other)
47
49
  end
48
50
  end
49
51
 
50
- # @param [TemporalAmount, Numeric] other
52
+ # @param [TemporalAmount, Numeric, QuantityType] other
51
53
  # If other is a Numeric, it's interpreted as days.
52
54
  # @return [LocalDate]
53
55
  def +(other)
@@ -56,6 +58,8 @@ module OpenHAB
56
58
  plus_days(other.to_days)
57
59
  when Numeric
58
60
  plus_days(other.to_i)
61
+ when QuantityType
62
+ plus_days(other.to_temporal_amount.to_days)
59
63
  else
60
64
  plus(other)
61
65
  end
@@ -67,23 +67,25 @@ module OpenHAB
67
67
  end
68
68
  end
69
69
 
70
- # @param [TemporalAmount, Numeric] other
70
+ # @param [TemporalAmount, Numeric, QuantityType] other
71
71
  # If other is a Numeric, it's interpreted as seconds.
72
72
  # @return [LocalTime]
73
73
  def -(other)
74
74
  return minus(other.seconds) if other.is_a?(Numeric)
75
75
  return self if other.is_a?(Period)
76
76
 
77
+ other = other.to_temporal_amount if other.is_a?(QuantityType)
77
78
  minus(other)
78
79
  end
79
80
 
80
- # @param [TemporalAmount, Numeric] other
81
+ # @param [TemporalAmount, Numeric, QuantityType] other
81
82
  # If other is a Numeric, it's interpreted as seconds.
82
83
  # @return [LocalTime]
83
84
  def +(other)
84
85
  return plus(other.seconds) if other.is_a?(Numeric)
85
86
  return self if other.is_a?(Period)
86
87
 
88
+ other = other.to_temporal_amount if other.is_a?(QuantityType)
87
89
  plus(other)
88
90
  end
89
91
 
@@ -16,11 +16,11 @@ module Java::JavaUtil::Map # rubocop:disable Style/ClassAndModuleChildren
16
16
  end
17
17
 
18
18
  def except(*keys)
19
- reject { |k, _v| keys.include?(k) }
19
+ reject { |k, _v| keys.include?(k) } # rubocop:disable Style/HashExcept
20
20
  end
21
21
 
22
22
  def slice(*keys)
23
- select { |k, _v| keys.include?(k) }
23
+ select { |k, _v| keys.include?(k) } # rubocop:disable Style/HashSlice
24
24
  end
25
25
 
26
26
  def transform_keys(hash2 = nil)
@@ -36,6 +36,7 @@ module OpenHAB
36
36
  # @return [Integer, nil]
37
37
  def <=>(other)
38
38
  return to_i <=> other if other.is_a?(Numeric)
39
+ return to_i <=> other.to_i if other.is_a?(Duration)
39
40
 
40
41
  super
41
42
  end
@@ -43,11 +44,13 @@ module OpenHAB
43
44
  #
44
45
  # Convert `self` and `other` to {Duration}, if `other` is a Numeric
45
46
  #
46
- # @param [Numeric] other
47
+ # @param [Numeric, Duration] other
47
48
  # @return [Array, nil]
48
49
  #
49
50
  def coerce(other)
50
- [other.seconds, to_i.seconds] if other.is_a?(Numeric)
51
+ return [other.seconds, to_i.seconds] if other.is_a?(Numeric)
52
+
53
+ [other, to_i.seconds] if other.is_a?(Duration)
51
54
  end
52
55
 
53
56
  {
@@ -55,11 +58,11 @@ module OpenHAB
55
58
  minus: :-
56
59
  }.each do |java_op, ruby_op|
57
60
  # def +(other)
58
- # if other.is_a?(Period)
61
+ # if other.is_a?(Period) || other.is_a?(Duration)
59
62
  # plus(other)
60
63
  # elsif other.is_a?(Numeric)
61
64
  # self + other.seconds
62
- # elsif other.respond_to?(:coerce) && (rhs, lhs = other.coerce(self))
65
+ # elsif other.respond_to?(:coerce) && (lhs, rhs = other.coerce(self))
63
66
  # lhs + rhs
64
67
  # else
65
68
  # raise TypeError, "#{other.class} can't be coerced into Period"
@@ -71,7 +74,7 @@ module OpenHAB
71
74
  #{java_op}(other)
72
75
  elsif other.is_a?(Numeric)
73
76
  self #{ruby_op} other.seconds
74
- elsif other.respond_to?(:coerce) && (rhs, lhs = other.coerce(self))
77
+ elsif other.respond_to?(:coerce) && (lhs, rhs = other.coerce(self))
75
78
  lhs #{ruby_op} rhs
76
79
  else
77
80
  raise TypeError, "\#{other.class} can't be coerced into Period"
@@ -84,7 +87,7 @@ module OpenHAB
84
87
  def *(other)
85
88
  if other.is_a?(Integer)
86
89
  multipliedBy(other)
87
- elsif other.respond_to?(:coerce) && (rhs, lhs = other.coerce(self))
90
+ elsif other.respond_to?(:coerce) && (lhs, rhs = other.coerce(self))
88
91
  lhs * rhs
89
92
  else
90
93
  raise TypeError, "#{other.class} can't be coerced into Period"
@@ -28,6 +28,11 @@ module OpenHAB
28
28
  def inspect
29
29
  to_s
30
30
  end
31
+
32
+ # @return [self]
33
+ def to_temporal_amount
34
+ self
35
+ end
31
36
  end
32
37
  end
33
38
  end
@@ -39,27 +39,33 @@ module OpenHAB
39
39
  # @return [Month]
40
40
  alias_method :to_month, :month
41
41
 
42
- # @param [TemporalAmount, #to_zoned_date_time, Numeric] other
42
+ # @param [TemporalAmount, #to_zoned_date_time, Numeric, QuantityType] other
43
43
  # If other is a Numeric, it's interpreted as seconds.
44
44
  # @return [Duration] If other responds to #to_zoned_date_time
45
- # @return [ZonedDateTime] If other is a TemporalAmount
45
+ # @return [ZonedDateTime] If other is a TemporalAmount or a Time QuantityType
46
46
  def -(other)
47
47
  if other.respond_to?(:to_zoned_date_time)
48
48
  java.time.Duration.between(other.to_zoned_date_time, self)
49
49
  elsif other.is_a?(Numeric)
50
50
  minus(other.seconds)
51
+ elsif other.is_a?(QuantityType)
52
+ minus(other.to_temporal_amount)
51
53
  else
52
54
  minus(other)
53
55
  end
54
56
  end
55
57
 
56
- # @param [TemporalAmount, Numeric] other
58
+ # @param [TemporalAmount, Numeric, QuantityType] other
57
59
  # If other is a Numeric, it's interpreted as seconds.
58
60
  # @return [ZonedDateTime]
59
61
  def +(other)
60
- return plus(other.seconds) if other.is_a?(Numeric)
61
-
62
- plus(other)
62
+ if other.is_a?(Numeric)
63
+ plus(other.seconds)
64
+ elsif other.is_a?(QuantityType)
65
+ plus(other.to_temporal_amount)
66
+ else
67
+ plus(other)
68
+ end
63
69
  end
64
70
 
65
71
  #
@@ -12,11 +12,11 @@ class Date
12
12
  #
13
13
  # Extends {#+} to allow adding a {java.time.temporal.TemporalAmount TemporalAmount}
14
14
  #
15
- # @param [java.time.temporal.TemporalAmount] other
16
- # @return [LocalDate] If other is a {java.time.temporal.TemporalAmount TemporalAmount}
15
+ # @param [java.time.temporal.TemporalAmount, QuantityType] other
16
+ # @return [LocalDate] If other is a {java.time.temporal.TemporalAmount TemporalAmount} or a Time {QuantityType}
17
17
  #
18
18
  def plus_with_temporal(other)
19
- return to_local_date + other if other.is_a?(java.time.temporal.TemporalAmount)
19
+ return to_local_date + other.to_temporal_amount if other.respond_to?(:to_temporal_amount)
20
20
 
21
21
  plus_without_temporal(other)
22
22
  end
@@ -26,13 +26,14 @@ class Date
26
26
  #
27
27
  # Extends {#-} to allow subtracting a {java.time.temporal.TemporalAmount TemporalAmount}
28
28
  #
29
- # @param [java.time.temporal.TemporalAmount] other
30
- # @return [LocalDate] If other is a {java.time.temporal.TemporalAmount TemporalAmount}
29
+ # @param [java.time.temporal.TemporalAmount, QuantityType] other
30
+ # @return [LocalDate] If other is a {java.time.temporal.TemporalAmount TemporalAmount} or a Time {QuantityType}
31
31
  #
32
32
  def minus_with_temporal(other)
33
- case other
34
- when java.time.temporal.TemporalAmount, java.time.LocalDate
33
+ if other.instance_of?(java.time.LocalDate)
35
34
  to_local_date - other
35
+ elsif other.respond_to?(:to_temporal_amount)
36
+ to_local_date - other.to_temporal_amount
36
37
  else
37
38
  minus_without_temporal(other)
38
39
  end
@@ -15,7 +15,7 @@ class DateTime < Date
15
15
 
16
16
  # (see Time#plus_with_temporal)
17
17
  def plus_with_temporal(other)
18
- return to_zoned_date_time + other if other.is_a?(java.time.temporal.TemporalAmount)
18
+ return to_zoned_date_time + other.to_temporal_amount if other.respond_to?(:to_temporal_amount)
19
19
 
20
20
  plus_without_temporal(other)
21
21
  end
@@ -24,7 +24,7 @@ class DateTime < Date
24
24
 
25
25
  # (see Time#minus_with_temporal)
26
26
  def minus_with_temporal(other)
27
- return to_zoned_date_time - other if other.is_a?(java.time.temporal.TemporalAmount)
27
+ return to_zoned_date_time - other.to_temporal_amount if other.respond_to?(:to_temporal_amount)
28
28
 
29
29
  # Exclude subtracting against the same class
30
30
  if other.respond_to?(:to_zoned_date_time) && !other.is_a?(self.class)
@@ -18,7 +18,7 @@ class Time
18
18
  # @return [Time] If other is a Numeric
19
19
  #
20
20
  def plus_with_temporal(other)
21
- return to_zoned_date_time + other if other.is_a?(java.time.temporal.TemporalAmount)
21
+ return to_zoned_date_time + other.to_temporal_amount if other.respond_to?(:to_temporal_amount)
22
22
 
23
23
  plus_without_temporal(other)
24
24
  end
@@ -53,7 +53,7 @@ class Time
53
53
  # @return [Float] If other is a Time
54
54
  #
55
55
  def minus_with_temporal(other)
56
- return to_zoned_date_time - other if other.is_a?(java.time.temporal.TemporalAmount)
56
+ return to_zoned_date_time - other.to_temporal_amount if other.respond_to?(:to_temporal_amount)
57
57
 
58
58
  # Exclude subtracting against the same class
59
59
  if other.respond_to?(:to_zoned_date_time) && !other.is_a?(self.class)
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- Dir[File.expand_path("core_ext/**/*.rb", __dir__)].sort.each do |f|
3
+ Dir[File.expand_path("core_ext/**/*.rb", __dir__)].each do |f|
4
4
  require f
5
5
  end
6
6
 
@@ -107,7 +107,7 @@ module OpenHAB
107
107
  verify: false)
108
108
  # Extract the named arguments into a hash
109
109
  @parameters << method(__method__).parameters
110
- .select { |param_type, _| param_type == :key }
110
+ .select { |param_type, _| param_type == :key } # rubocop:disable Style/HashSlice
111
111
  .to_h { |_, key| [key, binding.local_variable_get(key)] }
112
112
  .then do |p|
113
113
  p[:options] = p[:options].map do |opt_value, opt_label|