openhab-scripting 4.1.4 → 4.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. checksums.yaml +4 -4
  2. data/lib/openhab/core/entity_lookup.rb +1 -57
  3. data/lib/openhab/dsl/actions.rb +2 -3
  4. data/lib/openhab/dsl/dsl.rb +8 -12
  5. data/lib/openhab/dsl/group.rb +1 -5
  6. data/lib/openhab/dsl/items/color_item.rb +60 -0
  7. data/lib/openhab/dsl/items/comparable_item.rb +49 -0
  8. data/lib/openhab/dsl/items/contact_item.rb +41 -0
  9. data/lib/openhab/dsl/items/date_time_item.rb +64 -0
  10. data/lib/openhab/dsl/items/dimmer_item.rb +59 -0
  11. data/lib/openhab/dsl/items/ensure.rb +93 -0
  12. data/lib/openhab/dsl/items/generic_item.rb +174 -0
  13. data/lib/openhab/dsl/items/group_item.rb +121 -89
  14. data/lib/openhab/dsl/items/image_item.rb +5 -41
  15. data/lib/openhab/dsl/items/item_equality.rb +36 -0
  16. data/lib/openhab/dsl/items/item_registry.rb +49 -0
  17. data/lib/openhab/dsl/items/items.rb +81 -35
  18. data/lib/openhab/dsl/items/metadata.rb +325 -0
  19. data/lib/openhab/dsl/items/number_item.rb +6 -312
  20. data/lib/openhab/dsl/items/numeric_item.rb +68 -0
  21. data/lib/openhab/dsl/items/persistence.rb +122 -0
  22. data/lib/openhab/dsl/items/player_item.rb +49 -40
  23. data/lib/openhab/dsl/items/rollershutter_item.rb +25 -77
  24. data/lib/openhab/dsl/items/string_item.rb +16 -58
  25. data/lib/openhab/dsl/items/switch_item.rb +62 -0
  26. data/lib/openhab/dsl/lazy_array.rb +8 -6
  27. data/lib/openhab/dsl/monkey_patch/events/events.rb +2 -2
  28. data/lib/openhab/dsl/monkey_patch/events/item_command.rb +67 -24
  29. data/lib/openhab/dsl/monkey_patch/events/item_event.rb +5 -5
  30. data/lib/openhab/dsl/monkey_patch/events/item_state.rb +10 -11
  31. data/lib/openhab/dsl/monkey_patch/events/item_state_changed.rb +10 -11
  32. data/lib/openhab/dsl/monkey_patch/ruby/number.rb +25 -2
  33. data/lib/openhab/dsl/monkey_patch/ruby/ruby.rb +0 -3
  34. data/lib/openhab/dsl/monkey_patch/ruby/string.rb +24 -24
  35. data/lib/openhab/dsl/rules/terse.rb +24 -0
  36. data/lib/openhab/dsl/states.rb +1 -1
  37. data/lib/openhab/dsl/time_of_day.rb +3 -5
  38. data/lib/openhab/dsl/types/comparable_type.rb +21 -0
  39. data/lib/openhab/dsl/types/date_time_type.rb +334 -0
  40. data/lib/openhab/dsl/types/decimal_type.rb +187 -0
  41. data/lib/openhab/dsl/types/hsb_type.rb +201 -0
  42. data/lib/openhab/dsl/types/increase_decrease_type.rb +23 -0
  43. data/lib/openhab/dsl/types/next_previous_type.rb +23 -0
  44. data/lib/openhab/dsl/types/numeric_type.rb +39 -0
  45. data/lib/openhab/dsl/types/on_off_type.rb +29 -0
  46. data/lib/openhab/dsl/types/open_closed_type.rb +29 -0
  47. data/lib/openhab/dsl/types/percent_type.rb +70 -0
  48. data/lib/openhab/dsl/types/play_pause_type.rb +27 -0
  49. data/lib/openhab/dsl/types/quantity_type.rb +275 -0
  50. data/lib/openhab/dsl/types/refresh_type.rb +18 -0
  51. data/lib/openhab/dsl/types/rewind_fastforward_type.rb +33 -0
  52. data/lib/openhab/dsl/types/stop_move_type.rb +23 -0
  53. data/lib/openhab/dsl/types/string_type.rb +88 -0
  54. data/lib/openhab/dsl/types/type.rb +72 -0
  55. data/lib/openhab/dsl/types/types.rb +78 -0
  56. data/lib/openhab/dsl/types/un_def_type.rb +22 -0
  57. data/lib/openhab/dsl/types/up_down_type.rb +32 -0
  58. data/lib/openhab/dsl/units.rb +11 -6
  59. data/lib/openhab/version.rb +1 -1
  60. data/lib/openhab.rb +0 -1
  61. metadata +36 -28
  62. data/lib/openhab/dsl/items/datetime_item.rb +0 -75
  63. data/lib/openhab/dsl/items/item_command.rb +0 -90
  64. data/lib/openhab/dsl/items/item_delegate.rb +0 -125
  65. data/lib/openhab/dsl/monkey_patch/items/contact_item.rb +0 -51
  66. data/lib/openhab/dsl/monkey_patch/items/dimmer_item.rb +0 -140
  67. data/lib/openhab/dsl/monkey_patch/items/items.rb +0 -142
  68. data/lib/openhab/dsl/monkey_patch/items/metadata.rb +0 -328
  69. data/lib/openhab/dsl/monkey_patch/items/persistence.rb +0 -123
  70. data/lib/openhab/dsl/monkey_patch/items/switch_item.rb +0 -71
  71. data/lib/openhab/dsl/monkey_patch/ruby/range.rb +0 -47
  72. data/lib/openhab/dsl/monkey_patch/ruby/time.rb +0 -32
  73. data/lib/openhab/dsl/monkey_patch/types/decimal_type.rb +0 -97
  74. data/lib/openhab/dsl/monkey_patch/types/increase_decrease_type.rb +0 -23
  75. data/lib/openhab/dsl/monkey_patch/types/next_previous_type.rb +0 -23
  76. data/lib/openhab/dsl/monkey_patch/types/on_off_type.rb +0 -79
  77. data/lib/openhab/dsl/monkey_patch/types/open_closed_type.rb +0 -71
  78. data/lib/openhab/dsl/monkey_patch/types/percent_type.rb +0 -77
  79. data/lib/openhab/dsl/monkey_patch/types/play_pause_type.rb +0 -23
  80. data/lib/openhab/dsl/monkey_patch/types/quantity_type.rb +0 -69
  81. data/lib/openhab/dsl/monkey_patch/types/refresh_type.rb +0 -23
  82. data/lib/openhab/dsl/monkey_patch/types/rewind_fastforward_type.rb +0 -23
  83. data/lib/openhab/dsl/monkey_patch/types/stop_move_type.rb +0 -23
  84. data/lib/openhab/dsl/monkey_patch/types/types.rb +0 -15
  85. data/lib/openhab/dsl/monkey_patch/types/up_down_type.rb +0 -72
  86. data/lib/openhab/dsl/types/datetime.rb +0 -338
  87. data/lib/openhab/dsl/types/quantity.rb +0 -300
@@ -1,338 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'java'
4
- require 'forwardable'
5
- require 'time'
6
-
7
- module OpenHAB
8
- module DSL
9
- module Types
10
- #
11
- # Ruby implementation for OpenHAB DateTimeType
12
- #
13
- # @author Anders Alfredsson
14
- #
15
- # rubocop: disable Metrics/ClassLength
16
- # Disabled because this class has a single responsibility, there does not appear a logical
17
- # way of breaking it up into multiple classes
18
- class DateTime
19
- extend Forwardable
20
- include Comparable
21
- include OpenHAB::Log
22
-
23
- def_delegator :datetime, :to_s
24
- def_delegator :zoned_date_time, :month_value, :month
25
- def_delegator :zoned_date_time, :day_of_month, :mday
26
- def_delegator :zoned_date_time, :day_of_year, :yday
27
- def_delegator :zoned_date_time, :minute, :min
28
- def_delegator :zoned_date_time, :second, :sec
29
- def_delegator :zoned_date_time, :nano, :nsec
30
- def_delegator :zoned_date_time, :to_epoch_second, :to_i
31
- alias inspect to_s
32
- alias day mday
33
-
34
- java_import Java::OrgOpenhabCoreLibraryTypes::DateTimeType
35
- java_import java.time.ZonedDateTime
36
- java_import java.time.Instant
37
- java_import java.time.ZoneId
38
- java_import java.time.ZoneOffset
39
- java_import java.time.Duration
40
-
41
- #
42
- # Regex expression to identify strings defining a time in hours, minutes and optionally seconds
43
- #
44
- TIME_ONLY_REGEX = /\A\d\d:\d\d(:\d\d)?\Z/.freeze
45
-
46
- #
47
- # Regex expression to identify strings defining a time in hours, minutes and optionally seconds
48
- #
49
- DATE_ONLY_REGEX = /\A\d{4}-\d\d-\d\d\Z/.freeze
50
-
51
- attr_reader :datetime
52
-
53
- #
54
- # Create a new DateTime instance wrapping an OpenHAB DateTimeType
55
- #
56
- # @param [Java::org::openhab::core::library::types::DateTimeType] datetime The DateTimeType instance to
57
- # delegate to, or an object that can be converted to a DateTimeType
58
- #
59
- def initialize(datetime)
60
- @datetime = case datetime
61
- when DateTimeType
62
- datetime
63
- when ZonedDateTime
64
- DateTimeType.new(datetime)
65
- else
66
- raise "Unexpected type #{datetime.class} provided to DateTime initializer"
67
- end
68
- end
69
-
70
- #
71
- # Compare thes DateTime object to another
72
- #
73
- # @param [Object] other Other object to compare against
74
- #
75
- # @return [Integer] -1, 0 or 1 depending on the outcome
76
- #
77
- def <=>(other)
78
- if other.respond_to?(:zoned_date_time)
79
- return zoned_date_time.to_instant.compare_to(other.zoned_date_time.to_instant)
80
- end
81
-
82
- case other
83
- when TimeOfDay::TimeOfDay, TimeOfDay::TimeOfDayRangeElement then to_tod <=> other
84
- when String then self <=> DateTime.parse(DATE_ONLY_REGEX.match?(other) ? "#{other}'T'00:00:00#{zone}" : other)
85
- else
86
- self <=> DateTime.from(other)
87
- end
88
- end
89
-
90
- #
91
- # Adds another object to this DateTime
92
- #
93
- # @param [Object] other Object to add to this. Can be a Numeric, another DateTime/Time/DateTimeType, a
94
- # Duration or a String that can be parsed into a DateTimeType or Time object
95
- #
96
- # @return [DateTime] A new DateTime object representing the result of the calculation
97
- #
98
- def +(other)
99
- logger.trace("Adding #{other} (#{other.class}) to #{self}")
100
- case other
101
- when Numeric then DateTime.from(to_time + other)
102
- when DateTime, Time then self + other.to_f
103
- when DateTimeType, String then self + DateTime.from(other).to_f
104
- when Duration then DateTime.new(zoned_date_time.plus(other))
105
- end
106
- end
107
-
108
- #
109
- # Subtracts another object from this DateTime
110
- #
111
- # @param [Object] other Object to subtract fom this. Can be a Numeric, another DateTime/Time/DateTimeType, a
112
- # Duration or a String that can be parsed into a DateTimeType or Time object
113
- #
114
- # @return [DateTime, Float] A new DateTime object representing the result of the calculation, or a Float
115
- # representing the time difference in seconds if the subtraction is between two time objects
116
- #
117
- def -(other)
118
- logger.trace("Subtracting #{other} (#{other.class}) from self")
119
- case other
120
- when Numeric then DateTime.from(to_time - other)
121
- when String
122
- dt = DateTime.parse(other)
123
- TIME_ONLY_REGEX.match?(other) ? self - dt.to_f : time_diff(dt)
124
- when Duration then DateTime.new(zoned_date_time.minus(other))
125
- when Time, DateTime, DateTimeType, DateTimeItem then time_diff(other)
126
- end
127
- end
128
-
129
- #
130
- # Convert this DateTime to a ruby Time object
131
- #
132
- # @return [Time] A Time object representing the same instant and timezone
133
- #
134
- def to_time
135
- Time.at(to_i, nsec, :nsec).localtime(utc_offset)
136
- end
137
-
138
- #
139
- # Convert the time part of this DateTime to a TimeOfDay object
140
- #
141
- # @return [TimeOfDay] A TimeOfDay object representing the time
142
- #
143
- def to_time_of_day
144
- TimeOfDay::TimeOfDay.new(h: hour, m: minute, s: second)
145
- end
146
-
147
- alias to_tod to_time_of_day
148
-
149
- #
150
- # Returns the value of time as a floating point number of seconds since the Epoch
151
- #
152
- # @return [Float] Number of seconds since the Epoch, with nanosecond presicion
153
- #
154
- def to_f
155
- zoned_date_time.to_epoch_second + (zoned_date_time.nano / 1_000_000_000)
156
- end
157
-
158
- #
159
- # The ZonedDateTime representing the state
160
- #
161
- # @return [Java::java::time::ZonedDateTime] ZonedDateTime representing the state
162
- #
163
- def zoned_date_time
164
- @datetime.zonedDateTime
165
- end
166
-
167
- alias to_zdt zoned_date_time
168
-
169
- #
170
- # The offset in seconds from UTC
171
- #
172
- # @return [Integer] The offset from UTC, in seconds
173
- #
174
- def utc_offset
175
- zoned_date_time.offset.total_seconds
176
- end
177
-
178
- #
179
- # Returns true if time represents a time in UTC (GMT)
180
- #
181
- # @return [Boolean] true if utc_offset == 0, false otherwise
182
- #
183
- def utc?
184
- utc_offset.zero?
185
- end
186
-
187
- #
188
- # Returns an integer representing the day of the week, 0..6, with Sunday == 0.
189
- #
190
- # @return [Integer] The day of week
191
- #
192
- def wday
193
- zoned_date_time.day_of_week.value % 7
194
- end
195
-
196
- #
197
- # The timezone
198
- #
199
- # @return [String] The timezone in `[+-]hh:mm(:ss)` format ('Z' for UTC) or nil if the Item has no state
200
- #
201
- def zone
202
- zoned_date_time.zone.id
203
- end
204
-
205
- #
206
- # Check if missing method can be delegated to other contained objects
207
- #
208
- # @param [String, Symbol] meth the method name to check for
209
- #
210
- # @return [Boolean] true if DateTimeType, ZonedDateTime or Time responds to the method, false otherwise
211
- #
212
- def respond_to_missing?(meth, *)
213
- @datetime.respond_to?(meth) ||
214
- zoned_date_time.respond_to?(meth) ||
215
- Time.instance_methods.include?(meth.to_sym)
216
- end
217
-
218
- #
219
- # Forward missing methods to the OpenHAB DateTimeType, its ZonedDateTime object or a ruby Time
220
- # object representing the same instant
221
- #
222
- # @param [String] meth method name
223
- # @param [Array] args arguments for method
224
- # @param [Proc] block <description>
225
- #
226
- # @return [Object] Value from delegated method in OpenHAB NumberItem
227
- #
228
- def method_missing(meth, *args, &block)
229
- if @datetime.respond_to?(meth)
230
- @datetime.__send__(meth, *args, &block)
231
- elsif zoned_date_time.respond_to?(meth)
232
- zoned_date_time.__send__(meth, *args, &block)
233
- elsif Time.instance_methods.include?(meth.to_sym)
234
- to_time.send(meth, *args, &block)
235
- else
236
- raise NoMethodError, "undefined method `#{meth}' for #{self.class}"
237
- end
238
- end
239
-
240
- #
241
- # Converts other objects to a DateTimeType
242
- #
243
- # @param [String, Numeric, Time] datetime an object that can be parsed or converted into
244
- # a DateTimeType
245
- #
246
- # @return [Java::org::openhab::core::library::types::DateTimeType] Object representing the same time
247
- #
248
- def self.from(datetime)
249
- case datetime
250
- when String
251
- parse(datetime)
252
- when Numeric
253
- from_numeric(datetime)
254
- when Time
255
- from_time(datetime)
256
- else
257
- raise "Cannot convert #{datetime.class} to DateTime"
258
- end
259
- end
260
-
261
- #
262
- # Converts a Numeric into a DateTimeType
263
- #
264
- # @param [Numeric] numeric A Integer or Float representing the number of seconds since the epoch
265
- #
266
- # @return [Java::org::openhab::core::library::types::DateTimeType] Object representing the same time
267
- #
268
- def self.from_numeric(numeric)
269
- case numeric
270
- when Integer
271
- DateTime.new(ZonedDateTime.ofInstant(Instant.ofEpochSecond(datetime), ZoneId.systemDefault))
272
- else
273
- DateTime.new(ZonedDateTime.ofInstant(Instant.ofEpochSecond(datetime.to_i,
274
- ((datetime % 1) * 1_000_000_000).to_i),
275
- ZoneId.systemDefault))
276
- end
277
- end
278
-
279
- #
280
- # Converts a ruby Time object to an OpenHAB DateTimeType
281
- #
282
- # @param [Time] time The Time object to be converted
283
- #
284
- # @return [Java::org::openhab::core::library::types::DateTimeType] Object representing the same time
285
- #
286
- def self.from_time(time)
287
- instant = Instant.ofEpochSecond(time.to_i, time.nsec)
288
- zone_id = ZoneId.of_offset('UTC', ZoneOffset.of_total_seconds(time.utc_offset))
289
- DateTime.new(ZonedDateTime.ofInstant(instant, zone_id))
290
- end
291
-
292
- #
293
- # Parses a string representing a time into an OpenHAB DateTimeType. First tries to parse it
294
- # using the DateTimeType's parser, then falls back to the ruby Time.parse
295
- #
296
- # @param [String] time_string The string to be parsed
297
- #
298
- # @return [Java::org::openhab::core::library::types::DateTimeType] Object representing the same time
299
- #
300
- def self.parse(time_string)
301
- time_string += 'Z' if TIME_ONLY_REGEX.match?(time_string)
302
- DateTime.new(DateTimeType.new(time_string))
303
- rescue Java::JavaLang::StringIndexOutOfBoundsException, Java::JavaLang::IllegalArgumentException
304
- # Try ruby's Time.parse if OpenHAB's DateTimeType parser fails
305
- begin
306
- time = Time.parse(time_string)
307
- DateTime.from(time)
308
- rescue ArgumentError
309
- raise "Unable to parse #{time_string} into a DateTime"
310
- end
311
- end
312
-
313
- private
314
-
315
- #
316
- # Calculates the difference in time between this instance and another time object
317
- #
318
- # @param [Time, DateTime, DateTimeItem, Java::org::openhab::core::library::types::DateTimeType] time_obj
319
- # The other time object to subtract from self
320
- #
321
- # @return [Float] The time difference between the two objects, in seconds
322
- #
323
- def time_diff(time_obj)
324
- logger.trace("Calculate time difference between #{self} and #{time_obj}")
325
- case time_obj
326
- when Time
327
- to_time - time_obj
328
- when DateTime, DateTimeItem
329
- self - time_obj.to_time
330
- when DateTimeType
331
- self - DateTime.new(time_obj).to_time
332
- end
333
- end
334
- end
335
- end
336
- end
337
- end
338
- # rubocop: enable Metrics/ClassLength
@@ -1,300 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'java'
4
- require 'forwardable'
5
-
6
- module OpenHAB
7
- module DSL
8
- #
9
- # Ruby implementation of OpenHAB Types
10
- #
11
- module Types
12
- #
13
- # Ruby implementation for OpenHAB quantities
14
- #
15
- # rubocop: disable Metrics/ClassLength
16
- # Disabled because this class has a single responsibility, there does not appear a logical
17
- # way of breaking it up into multiple classes
18
- class Quantity < Numeric
19
- extend Forwardable
20
- include OpenHAB::Log
21
-
22
- def_delegator :@quantity, :to_s
23
- def_delegators '@quantity.double_value', :positive?, :negative?, :zero?
24
-
25
- java_import org.openhab.core.library.types.QuantityType
26
- java_import org.openhab.core.library.types.DecimalType
27
- java_import org.openhab.core.types.util.UnitUtils
28
- java_import org.openhab.core.library.unit.Units
29
-
30
- # @return [Hash] Mapping of operation symbols to BigDecimal methods
31
- OPERATIONS = {
32
- '+' => 'add',
33
- '-' => 'subtract',
34
- '*' => 'multiply',
35
- '/' => 'divide'
36
- }.freeze
37
-
38
- private_constant :OPERATIONS
39
-
40
- attr_reader :quantity
41
-
42
- #
43
- # Create a new Quantity
44
- #
45
- # @param [object] quantity String,QuantityType or Numeric to be this quantity
46
- #
47
- # Cop disabled, case statement is compact and idiomatic
48
- def initialize(quantity)
49
- @quantity = case quantity
50
- when String then QuantityType.new(quantity)
51
- when QuantityType then quantity
52
- when NumberItem, Numeric then QuantityType.new(quantity.to_d.to_java, Units::ONE)
53
- else raise ArgumentError, "Unexpected type #{quantity.class} provided to Quantity initializer"
54
- end
55
- super()
56
- end
57
-
58
- #
59
- # Convert this quantity into a another unit
60
- #
61
- # @param [Object] other String or Unit to convert to
62
- #
63
- # @return [Quantity] This quantity converted to another unit
64
- #
65
- def |(other)
66
- other = UnitUtils.parse_unit(other) if other.is_a? String
67
-
68
- Quantity.new(quantity.to_unit(other))
69
- end
70
-
71
- #
72
- # Compare this quantity
73
- #
74
- # @param [Object] other object to compare to
75
- #
76
- # @return [Integer] -1,0,1 if this object is less than, equal to, or greater than the supplied object,
77
- # nil if it cannot be compared
78
- #
79
- def <=>(other)
80
- logger.trace("Comparing #{self} to #{other}")
81
- my_qt, other_qt = unitize(*to_qt(coerce(other).reverse))
82
- my_qt.compare_to(other_qt)
83
- end
84
-
85
- #
86
- # Coerce other object into a Quantity
87
- #
88
- # @param [Object] other object to convert to Quantity
89
- #
90
- # @return [Array] of self and other object as Quantity types, nil if object cannot be coerced
91
- #
92
- def coerce(other)
93
- logger.trace("Coercing #{self} as a request from #{other.class}")
94
- case other
95
- when Quantity then [other.quantity, quantity]
96
- when QuantityType then [other, quantity]
97
- when DecimalType then [Quantity.new(other.to_big_decimal.to_d), quantity]
98
- when NumberItem then [other.to_qt.quantity, quantity]
99
- when Numeric, String then [Quantity.new(other), self]
100
- end
101
- end
102
-
103
- #
104
- # Forward missing methods to Openhab Quantity Item if they are defined
105
- #
106
- # @param [String] meth name of method invoked
107
- # @param [Array] args arguments to invoked method
108
- # @param [Proc] block block passed ot method
109
- #
110
- # @return [Object] result of delegation
111
- #
112
- def method_missing(meth, *args, &block)
113
- logger.trace("Method missing, performing dynamic lookup for: #{meth}")
114
- if quantity.respond_to?(meth)
115
- quantity.__send__(meth, *args, &block)
116
- elsif ::Kernel.method_defined?(meth) || ::Kernel.private_method_defined?(meth)
117
- ::Kernel.instance_method(meth).bind_call(self, *args, &block)
118
- else
119
- super(meth, *args, &block)
120
- end
121
- end
122
-
123
- #
124
- # Checks if this method responds to the missing method
125
- #
126
- # @param [String] method_name Name of the method to check
127
- # @param [Boolean] _include_private boolean if private methods should be checked
128
- #
129
- # @return [Boolean] true if this object will respond to the supplied method, false otherwise
130
- #
131
- def respond_to_missing?(method_name, _include_private = false)
132
- quantity.respond_to?(method_name) ||
133
- ::Kernel.method_defined?(method_name) ||
134
- ::Kernel.private_method_defined?(method_name)
135
- end
136
-
137
- #
138
- # Negate the quantity
139
- #
140
- # @return [Quantity] This quantity negated
141
- #
142
- def -@
143
- Quantity.new(quantity.negate)
144
- end
145
-
146
- OPERATIONS.each do |operation, method|
147
- define_method(operation) do |other|
148
- logger.trace do
149
- "Executing math operation '#{operation}' on quantity #{inspect} "\
150
- "with other type #{other.class} and value #{other.inspect}"
151
- end
152
-
153
- a, b = to_qt(coerce(other).reverse)
154
- logger.trace("Coerced a='#{a}' with b='#{b}'")
155
- a, b = unitize(a, b, operation)
156
- logger.trace("Unitized a='#{a}' b='#{b}'")
157
- logger.trace("Performing operation '#{operation}' with method '#{method}' on a='#{a}' with b='#{b}'")
158
- Quantity.new(a.public_send(method, b))
159
- end
160
- end
161
-
162
- #
163
- # Provide details about quantity object
164
- #
165
- # @return [String] Representing details about the quantity object
166
- #
167
- def inspect
168
- if @quantity.unit == Units::ONE
169
- "unit=#{@quantity.unit}, value=#{@quantity.to_string}"
170
- else
171
- @quantity.to_string
172
- end
173
- end
174
-
175
- private
176
-
177
- # @return [Array] Array of strings for operations for which the operands will not be unitized
178
- DIMENSIONLESS_NON_UNITIZED_OPERATIONS = %w[* /].freeze
179
-
180
- # Dimensionless numbers should only be unitzed for addition and subtraction
181
-
182
- #
183
- # Convert one or more Quantity obects to the underlying quantitytypes
184
- #
185
- # @param [Array] quanities Array of either Quantity or QuantityType objects
186
- #
187
- # @return [Array] Array of QuantityType objects
188
- #
189
- def to_qt(*quantities)
190
- [quantities].flatten.compact.map { |item| item.is_a?(Quantity) ? item.quantity : item }
191
- end
192
-
193
- #
194
- # Checks if an item should be unitized
195
- #
196
- # @param [Quantity] quantity to check
197
- # @param [String] operation quantity is being used with
198
- #
199
- # @return [Boolean] True if the quantity should be unitzed based on the unit and operation, false otherwise
200
- #
201
- def unitize?(quantity, operation)
202
- !(quantity.unit == Units::ONE && DIMENSIONLESS_NON_UNITIZED_OPERATIONS.include?(operation))
203
- end
204
-
205
- #
206
- # Convert the unit for the quantity
207
- #
208
- # @param [Quantity] quantity being converted
209
- #
210
- # @return [Quantity] Quantity coverted to unit set by unit block
211
- #
212
- def convert_unit(quantity)
213
- return quantity unless unit?
214
-
215
- case quantity.unit
216
- when unit
217
- quantity
218
- when Units::ONE
219
- convert_unit_from_dimensionless(quantity, unit)
220
- else
221
- convert_unit_from_dimensioned(quantity, unit)
222
- end
223
- end
224
-
225
- #
226
- # Converts a dimensioned quantity to a specific unit
227
- #
228
- # @param [Quantity] quantity to convert
229
- # @param [Unit] unit to convert to
230
- #
231
- # @return [Java::org::openhab::core::library::types::QuantityType] converted quantity
232
- #
233
- def convert_unit_from_dimensioned(quantity, unit)
234
- logger.trace("Converting dimensioned item #{inspect} to #{unit}")
235
- quantity.to_unit(unit).tap do |converted|
236
- raise "Conversion from #{quantity.unit} to #{unit} failed" unless converted
237
- end
238
- end
239
-
240
- #
241
- # Converts a dimensionless quantity to a unit
242
- #
243
- # @param [Quantity] quantity to convert
244
- # @param [Unit] unit to convert to
245
- #
246
- # @return [Java::org::openhab::core::library::types::QuantityType] converted quantity
247
- #
248
- def convert_unit_from_dimensionless(quantity, unit)
249
- logger.trace("Converting dimensionless #{quantity} to #{unit}")
250
- QuantityType.new(quantity.to_big_decimal, unit)
251
- end
252
-
253
- #
254
- # Convert quantities to appropriate units
255
- #
256
- # @param [Quantity] quantity_a Quantity on left side of operation
257
- # @param [Quantity] quantity_b Quantity on right side of operation
258
- # @param [String] operation Math operation
259
- # @yield [quantity_a, quantity_b] yields unitized versions of supplied quantities
260
- #
261
- # @return [Array, Object] of quantites in correct units for the supplied operation and the unit
262
- # or the result of the block if a block is given
263
- #
264
- def unitize(quantity_a, quantity_b, operation = nil)
265
- logger.trace("Unitizing (#{quantity_a}) and (#{quantity_b})")
266
- quantity_a, quantity_b = [quantity_a, quantity_b].map do |qt|
267
- unitize?(qt, operation) ? convert_unit(qt) : qt.to_big_decimal
268
- end
269
-
270
- # Make sure the operation is called on the QuantityType
271
- if quantity_a.is_a?(Java::JavaMath::BigDecimal) && quantity_b.is_a?(QuantityType) && operation == '*'
272
- quantity_a, quantity_b = [quantity_b, quantity_a]
273
- end
274
- return yield quantity_a, quantity_b if block_given?
275
-
276
- [quantity_a, quantity_b]
277
- end
278
-
279
- #
280
- # Get the unit from the current thread local variable
281
- #
282
- # @return [Object] Unit or string representation of Unit, or nil if not set
283
- #
284
- def unit
285
- Thread.current.thread_variable_get(:unit)
286
- end
287
-
288
- #
289
- # Is a unit set for this thread
290
- #
291
- # @return [boolean] true if a unit is set by this thread, false otherwise
292
- #
293
- def unit?
294
- unit != nil
295
- end
296
- end
297
- end
298
- end
299
- end
300
- # rubocop: enable Metrics/ClassLength