openhab-scripting 4.1.4 → 4.2.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 (81) hide show
  1. checksums.yaml +4 -4
  2. data/lib/openhab/core/entity_lookup.rb +1 -57
  3. data/lib/openhab/dsl/dsl.rb +6 -12
  4. data/lib/openhab/dsl/group.rb +1 -5
  5. data/lib/openhab/dsl/items/comparable_item.rb +49 -0
  6. data/lib/openhab/dsl/items/contact_item.rb +41 -0
  7. data/lib/openhab/dsl/items/date_time_item.rb +64 -0
  8. data/lib/openhab/dsl/items/dimmer_item.rb +59 -0
  9. data/lib/openhab/dsl/items/generic_item.rb +197 -0
  10. data/lib/openhab/dsl/items/group_item.rb +56 -92
  11. data/lib/openhab/dsl/items/image_item.rb +5 -41
  12. data/lib/openhab/dsl/items/item_registry.rb +49 -0
  13. data/lib/openhab/dsl/items/items.rb +71 -35
  14. data/lib/openhab/dsl/items/metadata.rb +325 -0
  15. data/lib/openhab/dsl/items/number_item.rb +6 -312
  16. data/lib/openhab/dsl/items/numeric_item.rb +66 -0
  17. data/lib/openhab/dsl/items/persistence.rb +122 -0
  18. data/lib/openhab/dsl/items/player_item.rb +49 -40
  19. data/lib/openhab/dsl/items/rollershutter_item.rb +25 -77
  20. data/lib/openhab/dsl/items/string_item.rb +16 -58
  21. data/lib/openhab/dsl/items/switch_item.rb +62 -0
  22. data/lib/openhab/dsl/lazy_array.rb +8 -6
  23. data/lib/openhab/dsl/monkey_patch/events/events.rb +2 -2
  24. data/lib/openhab/dsl/monkey_patch/events/item_command.rb +67 -24
  25. data/lib/openhab/dsl/monkey_patch/events/item_event.rb +5 -5
  26. data/lib/openhab/dsl/monkey_patch/events/item_state.rb +10 -11
  27. data/lib/openhab/dsl/monkey_patch/events/item_state_changed.rb +10 -11
  28. data/lib/openhab/dsl/monkey_patch/ruby/number.rb +25 -2
  29. data/lib/openhab/dsl/monkey_patch/ruby/ruby.rb +0 -3
  30. data/lib/openhab/dsl/monkey_patch/ruby/string.rb +24 -24
  31. data/lib/openhab/dsl/states.rb +1 -1
  32. data/lib/openhab/dsl/time_of_day.rb +3 -5
  33. data/lib/openhab/dsl/types/comparable_type.rb +21 -0
  34. data/lib/openhab/dsl/types/date_time_type.rb +334 -0
  35. data/lib/openhab/dsl/types/decimal_type.rb +187 -0
  36. data/lib/openhab/dsl/types/increase_decrease_type.rb +23 -0
  37. data/lib/openhab/dsl/types/next_previous_type.rb +23 -0
  38. data/lib/openhab/dsl/types/numeric_type.rb +39 -0
  39. data/lib/openhab/dsl/types/on_off_type.rb +29 -0
  40. data/lib/openhab/dsl/types/open_closed_type.rb +29 -0
  41. data/lib/openhab/dsl/types/percent_type.rb +68 -0
  42. data/lib/openhab/dsl/types/play_pause_type.rb +27 -0
  43. data/lib/openhab/dsl/types/quantity_type.rb +275 -0
  44. data/lib/openhab/dsl/types/refresh_type.rb +18 -0
  45. data/lib/openhab/dsl/types/rewind_fastforward_type.rb +33 -0
  46. data/lib/openhab/dsl/types/stop_move_type.rb +23 -0
  47. data/lib/openhab/dsl/types/string_type.rb +88 -0
  48. data/lib/openhab/dsl/types/type.rb +72 -0
  49. data/lib/openhab/dsl/types/types.rb +77 -0
  50. data/lib/openhab/dsl/types/un_def_type.rb +22 -0
  51. data/lib/openhab/dsl/types/up_down_type.rb +32 -0
  52. data/lib/openhab/dsl/units.rb +11 -6
  53. data/lib/openhab/version.rb +1 -1
  54. data/lib/openhab.rb +0 -1
  55. metadata +31 -28
  56. data/lib/openhab/dsl/items/datetime_item.rb +0 -75
  57. data/lib/openhab/dsl/items/item_command.rb +0 -90
  58. data/lib/openhab/dsl/items/item_delegate.rb +0 -125
  59. data/lib/openhab/dsl/monkey_patch/items/contact_item.rb +0 -51
  60. data/lib/openhab/dsl/monkey_patch/items/dimmer_item.rb +0 -140
  61. data/lib/openhab/dsl/monkey_patch/items/items.rb +0 -142
  62. data/lib/openhab/dsl/monkey_patch/items/metadata.rb +0 -328
  63. data/lib/openhab/dsl/monkey_patch/items/persistence.rb +0 -123
  64. data/lib/openhab/dsl/monkey_patch/items/switch_item.rb +0 -71
  65. data/lib/openhab/dsl/monkey_patch/ruby/range.rb +0 -47
  66. data/lib/openhab/dsl/monkey_patch/ruby/time.rb +0 -32
  67. data/lib/openhab/dsl/monkey_patch/types/decimal_type.rb +0 -97
  68. data/lib/openhab/dsl/monkey_patch/types/increase_decrease_type.rb +0 -23
  69. data/lib/openhab/dsl/monkey_patch/types/next_previous_type.rb +0 -23
  70. data/lib/openhab/dsl/monkey_patch/types/on_off_type.rb +0 -79
  71. data/lib/openhab/dsl/monkey_patch/types/open_closed_type.rb +0 -71
  72. data/lib/openhab/dsl/monkey_patch/types/percent_type.rb +0 -77
  73. data/lib/openhab/dsl/monkey_patch/types/play_pause_type.rb +0 -23
  74. data/lib/openhab/dsl/monkey_patch/types/quantity_type.rb +0 -69
  75. data/lib/openhab/dsl/monkey_patch/types/refresh_type.rb +0 -23
  76. data/lib/openhab/dsl/monkey_patch/types/rewind_fastforward_type.rb +0 -23
  77. data/lib/openhab/dsl/monkey_patch/types/stop_move_type.rb +0 -23
  78. data/lib/openhab/dsl/monkey_patch/types/types.rb +0 -15
  79. data/lib/openhab/dsl/monkey_patch/types/up_down_type.rb +0 -72
  80. data/lib/openhab/dsl/types/datetime.rb +0 -338
  81. data/lib/openhab/dsl/types/quantity.rb +0 -300
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OpenHAB
4
+ module DSL
5
+ module Types
6
+ java_import org.openhab.core.library.types.PercentType
7
+
8
+ # global alias
9
+ ::PercentType = PercentType
10
+
11
+ # Adds methods to core OpenHAB PercentType to make it more natural in Ruby
12
+ class PercentType < DecimalType
13
+ # remove the JRuby default == so that we can inherit the Ruby method
14
+ remove_method :==
15
+
16
+ #
17
+ # Check if +ON+
18
+ #
19
+ # Note that +ON+ is defined as any value besides 0%.
20
+ #
21
+ # @return [Boolean]
22
+ #
23
+ def on?
24
+ as(OnOffType).on?
25
+ end
26
+
27
+ #
28
+ # Check if +OFF+
29
+ #
30
+ # Note that +OFF+ is defined as 0% exactly.
31
+ #
32
+ # @return [Boolean]
33
+ #
34
+ def off?
35
+ as(OnOffType).off?
36
+ end
37
+
38
+ #
39
+ # Check if +UP+
40
+ #
41
+ # Note that +UP+ is defined as 0% exactly.
42
+ #
43
+ # @return [Boolean]
44
+ #
45
+ def up?
46
+ !!as(UpDownType)&.up?
47
+ end
48
+
49
+ #
50
+ # Check if +DOWN+
51
+ #
52
+ # Note that +DOWN+ is defined as 100% exactly.
53
+ #
54
+ # @return [Boolean]
55
+ #
56
+ def down?
57
+ !!as(UpDownType)&.down?
58
+ end
59
+
60
+ # include the %
61
+ # @!visibility private
62
+ def to_s
63
+ "#{to_string}%"
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OpenHAB
4
+ module DSL
5
+ module Types
6
+ java_import org.openhab.core.library.types.PlayPauseType
7
+
8
+ # Adds methods to core OpenHAB PlayPauseType to make it more
9
+ # natural in Ruby
10
+ class PlayPauseType # rubocop:disable Lint/EmptyClass
11
+ # @!parse include Type
12
+
13
+ # @!method playing?
14
+ # Check if == +PLAY+
15
+ # @return [Boolean]
16
+
17
+ # @!parse alias play? playing?
18
+
19
+ # @!method paused?
20
+ # Check if == +PAUSE+
21
+ # @return [Boolean]
22
+
23
+ # @!parse alias pause? paused?
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,275 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'numeric_type'
4
+
5
+ module OpenHAB
6
+ module DSL
7
+ module Types
8
+ java_import org.openhab.core.library.types.QuantityType
9
+
10
+ # global alias
11
+ ::QuantityType = QuantityType
12
+
13
+ # @deprecated
14
+ # Backwards-compatible alias
15
+ Quantity = QuantityType
16
+
17
+ # Adds methods to core OpenHAB QuantityType to make it more natural in Ruby
18
+ class QuantityType # rubocop:disable Metrics/ClassLength
19
+ # @!parse include Type
20
+ include NumericType
21
+
22
+ # private alias
23
+ ONE = org.openhab.core.library.unit.Units::ONE
24
+ private_constant :ONE
25
+
26
+ #
27
+ # Convert this quantity into a another unit
28
+ #
29
+ # @param [Object] other String or Unit to convert to
30
+ #
31
+ # @return [QuantityType] This quantity converted to another unit
32
+ #
33
+ def |(other)
34
+ other = org.openhab.core.types.util.UnitUtils.parse_unit(other) if other.is_a?(String)
35
+
36
+ to_unit(other)
37
+ end
38
+
39
+ #
40
+ # Comparison
41
+ #
42
+ # @param [NumericType, Items::NumericItem, Numeric, String]
43
+ # other object to compare to
44
+ #
45
+ # @return [Integer, nil] -1, 0, +1 depending on whether +other+ is
46
+ # less than, equal to, or greater than self
47
+ #
48
+ # nil is returned if the two values are incomparable
49
+ #
50
+ def <=>(other) # rubocop:disable Metrics
51
+ logger.trace("(#{self.class}) #{self} <=> #{other} (#{other.class})")
52
+ if other.is_a?(self.class)
53
+ compare_to(other)
54
+ elsif other.is_a?(Items::NumericItem) ||
55
+ (other.is_a?(Items::GroupItem) && other.base_item.is_a?(NumericItem))
56
+ return nil unless other.state?
57
+
58
+ self <=> other.state
59
+ elsif other.respond_to?(:to_str)
60
+ compare_to(QuantityType.new(other.to_str))
61
+ elsif other.respond_to?(:to_d)
62
+ compare_to(QuantityType.new(other.to_d.to_java, Units.unit || unit))
63
+ elsif other.respond_to?(:coerce)
64
+ lhs, rhs = other.coerce(self)
65
+ lhs <=> rhs
66
+ end
67
+ end
68
+
69
+ #
70
+ # Type Coercion
71
+ #
72
+ # Coerce object to a QuantityType
73
+ #
74
+ # @param [Items::NumericItem, Numeric, Type, String] other object to
75
+ # coerce to a {QuantityType}
76
+ #
77
+ # if +other+ is a {Type}, +self+ will instead be coerced
78
+ # to that type to accomodate comparison with things such as {OnOffType}
79
+ #
80
+ # @return [[QuantityType, QuantityType]]
81
+ def coerce(other) # rubocop:disable Metrics
82
+ logger.trace("Coercing #{self} as a request from #{other.class}")
83
+ if other.is_a?(Items::NumericItem) ||
84
+ (other.is_a?(Items::GroupItem) && other.base_item.is_a?(Items::NumericItem))
85
+ raise TypeError, "can't convert #{UnDefType} into #{self.class}" unless other.state?
86
+
87
+ [other.state, self]
88
+ elsif other.is_a?(Type)
89
+ [other, as(other.class)]
90
+ elsif other.respond_to?(:to_d)
91
+ [QuantityType.new(other.to_d.to_java, ONE), self]
92
+ elsif other.is_a?(String)
93
+ [QuantityType.new(other), self]
94
+ else
95
+ raise TypeError, "can't convert #{other.class} into #{self.class}"
96
+ end
97
+ end
98
+
99
+ # arithmetic operators
100
+ alias -@ negate
101
+
102
+ {
103
+ :add => :+,
104
+ :subtract => :-
105
+ }.each do |java_op, ruby_op|
106
+ convert = 'self.class.new(other, Units.unit || unit)'
107
+
108
+ class_eval( # rubocop:disable Style/DocumentDynamicEvalDefinition https://github.com/rubocop/rubocop/issues/10179
109
+ # def +(other)
110
+ # logger.trace("#{self} + #{other} (#{other.class})")
111
+ # if other.is_a?(Items::NumericItem) ||
112
+ # (other.is_a?(Items::GroupItem) && other.base_item.is_a?(Items::NumericItem))
113
+ # self + other.state
114
+ # elsif other.is_a?(QuantityType)
115
+ # add_quantity(other)
116
+ # elsif other.is_a?(DecimalType)
117
+ # other = other.to_big_decimal
118
+ # add_quantity(self.class.new(other, Units.unit || unit))
119
+ # elsif other.is_a?(java.math.BigDecimal)
120
+ # add_quantity(self.class.new(other, Units.unit || unit))
121
+ # elsif other.respond_to?(:to_str)
122
+ # self + self.class.new(other)
123
+ # elsif other.respond_to?(:to_d)
124
+ # other = other.to_d.to_java
125
+ # add_quantity(self.class.new(other, Units.unit || unit))
126
+ # elsif other.respond_to?(:coerce)
127
+ # lhs, rhs = other.coerce(to_d)
128
+ # lhs = rhs
129
+ # else
130
+ # raise TypeError, "#{other.class} can't be coerced into #{self.class}"
131
+ # end
132
+ # end
133
+ <<~RUBY, __FILE__, __LINE__ + 1
134
+ def #{ruby_op}(other)
135
+ logger.trace("\#{self} #{ruby_op} \#{other} (\#{other.class})")
136
+ if other.is_a?(Items::NumericItem) ||
137
+ (other.is_a?(Items::GroupItem) && other.base_item.is_a?(Items::NumericItem))
138
+ self #{ruby_op} other.state
139
+ elsif other.is_a?(QuantityType)
140
+ #{java_op}_quantity(other)
141
+ elsif other.is_a?(DecimalType)
142
+ other = other.to_big_decimal
143
+ #{java_op}_quantity(#{convert})
144
+ elsif other.is_a?(java.math.BigDecimal)
145
+ #{java_op}_quantity(#{convert})
146
+ elsif other.respond_to?(:to_str)
147
+ self #{ruby_op} self.class.new(other)
148
+ elsif other.respond_to?(:to_d)
149
+ other = other.to_d.to_java
150
+ #{java_op}_quantity(#{convert})
151
+ elsif other.respond_to?(:coerce)
152
+ lhs, rhs = other.coerce(to_d)
153
+ lhs #{ruby_op} rhs
154
+ else
155
+ raise TypeError, "\#{other.class} can't be coerced into \#{self.class}"
156
+ end
157
+ end
158
+ RUBY
159
+ )
160
+ end
161
+
162
+ {
163
+ :multiply => :*,
164
+ :divide => :/
165
+ }.each do |java_op, ruby_op|
166
+ class_eval( # rubocop:disable Style/DocumentDynamicEvalDefinition https://github.com/rubocop/rubocop/issues/10179
167
+ # def *(other)
168
+ # logger.trace("#{self} * #{other} (#{other.class})")
169
+ # if other.is_a?(Items::NumericItem) ||
170
+ # (other.is_a?(Items::GroupItem) && other.base_item.is_a?(Items::NumericItem))
171
+ # self * other.state
172
+ # elsif other.is_a?(QuantityType)
173
+ # multiply_quantity(other)
174
+ # elsif other.is_a?(DecimalType)
175
+ # multiply(other.to_big_decimal)
176
+ # elsif other.is_a?(java.math.BigDecimal)
177
+ # multiply(other)
178
+ # elsif other.respond_to?(:to_str)
179
+ # self * self.class.new(other)
180
+ # elsif other.respond_to?(:to_d)
181
+ # multiply(other.to_d.to_java)
182
+ # elsif other.respond_to?(:coerce)
183
+ # lhs, rhs = other.coerce(to_d)
184
+ # lhs * rhs
185
+ # else
186
+ # raise TypeError, "#{other.class} can't be coerced into #{self.class}"
187
+ # end
188
+ # end
189
+ <<~RUBY, __FILE__, __LINE__ + 1
190
+ def #{ruby_op}(other)
191
+ logger.trace("\#{self} #{ruby_op} \#{other} (\#{other.class})")
192
+ if other.is_a?(Items::NumericItem) ||
193
+ (other.is_a?(Items::GroupItem) && other.base_item.is_a?(Items::NumericItem))
194
+ self #{ruby_op} other.state
195
+ elsif other.is_a?(QuantityType)
196
+ #{java_op}_quantity(other)
197
+ elsif other.is_a?(DecimalType)
198
+ #{java_op}(other.to_big_decimal)
199
+ elsif other.is_a?(java.math.BigDecimal)
200
+ #{java_op}(other)
201
+ elsif other.respond_to?(:to_str)
202
+ self #{ruby_op} self.class.new(other)
203
+ elsif other.respond_to?(:to_d)
204
+ #{java_op}(other.to_d.to_java)
205
+ elsif other.respond_to?(:coerce)
206
+ lhs, rhs = other.coerce(to_d)
207
+ lhs #{ruby_op} rhs
208
+ else
209
+ raise TypeError, "\#{other.class} can't be coerced into \#{self.class}"
210
+ end
211
+ end
212
+ RUBY
213
+ )
214
+ end
215
+
216
+ # if it's a dimensionless quantity, change the unit to match other_unit
217
+ # @!visibility private
218
+ def unitize(other_unit = unit)
219
+ # prefer converting to the thread-specified unit if there is one
220
+ other_unit = Units.unit || other_unit
221
+ logger.trace("Converting #{self} to #{other_unit}")
222
+
223
+ case unit
224
+ when ONE
225
+ QuantityType.new(to_big_decimal, other_unit)
226
+ when other_unit
227
+ self
228
+ else
229
+ to_unit(other_unit)
230
+ end
231
+ end
232
+
233
+ # if unit is +ONE+, return a plain Java BigDecimal
234
+ # @!visibility private
235
+ def deunitize
236
+ return to_big_decimal if unit == ONE
237
+
238
+ self
239
+ end
240
+
241
+ private
242
+
243
+ # do addition directly against a QuantityType while ensuring we unitize
244
+ # both sides
245
+ def add_quantity(other)
246
+ unitize(other.unit).add(other.unitize(unit))
247
+ end
248
+
249
+ # do subtraction directly against a QuantityType while ensuring we
250
+ # unitize both sides
251
+ def subtract_quantity(other)
252
+ unitize(other.unit).subtract(other.unitize(unit))
253
+ end
254
+
255
+ # do multiplication directly against a QuantityType while ensuring
256
+ # we deunitize both sides, and also invert the operation if one side
257
+ # isn't actually a unit
258
+ def multiply_quantity(other)
259
+ lhs = deunitize
260
+ rhs = other.deunitize
261
+ # reverse the arguments if it's multiplication and the LHS isn't a QuantityType
262
+ lhs, rhs = rhs, lhs if lhs.is_a?(java.math.BigDecimal)
263
+ # what a waste... using a QuantityType to multiply two dimensionless quantities
264
+ # have to make sure lhs is still a QuantityType in order to return a new
265
+ # QuantityType that's still dimensionless
266
+ lhs = other if lhs.is_a?(java.math.BigDecimal)
267
+
268
+ lhs.multiply(rhs)
269
+ end
270
+
271
+ alias divide_quantity divide
272
+ end
273
+ end
274
+ end
275
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OpenHAB
4
+ module DSL
5
+ module Types
6
+ java_import org.openhab.core.types.RefreshType
7
+
8
+ # Adds methods to core OpenHAB RefreshType to make it more natural in Ruby
9
+ class RefreshType # rubocop:disable Lint/EmptyClass
10
+ # @!parse include Type
11
+
12
+ # @!method refresh?
13
+ # Check if == +REFRESH+
14
+ # @return [Boolean]
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OpenHAB
4
+ module DSL
5
+ module Types
6
+ java_import org.openhab.core.library.types.RewindFastforwardType
7
+
8
+ # Adds methods to core OpenHAB RewindFastforwardType to make it more
9
+ # natural in Ruby
10
+ class RewindFastforwardType # rubocop:disable Lint/EmptyClass
11
+ # @!parse include Type
12
+
13
+ # @!method rewinding?
14
+ # Check if == +REWIND+
15
+ # @return [Boolean]
16
+
17
+ # @!parse alias rewind? rewinding?
18
+
19
+ # @!method fast_forwarding?
20
+ # Check if == +FASTFORWARD+
21
+ # @return [Boolean]
22
+
23
+ # @!parse alias fast_forward? fast_forwarding?
24
+
25
+ # @deprecated
26
+ # @!parse alias fastforward? fast_forwarding?
27
+
28
+ # @deprecated
29
+ # @!parse alias fastforwarding? fast_forwarding?
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OpenHAB
4
+ module DSL
5
+ module Types
6
+ java_import org.openhab.core.library.types.StopMoveType
7
+
8
+ # Adds methods to core OpenHAB StopMoveType to make it more
9
+ # natural in Ruby
10
+ class StopMoveType # rubocop:disable Lint/EmptyClass
11
+ # @!parse include Type
12
+
13
+ # @!method stop?
14
+ # Check if == +STOP+
15
+ # @return [Boolean]
16
+
17
+ # @!method move?
18
+ # Check if == +MOVE+
19
+ # @return [Boolean]
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'forwardable'
4
+
5
+ require_relative 'comparable_type'
6
+
7
+ module OpenHAB
8
+ module DSL
9
+ module Types
10
+ java_import org.openhab.core.library.types.StringType
11
+
12
+ #
13
+ # Add methods to core OpenHAB StringType to make it behave as a Ruby
14
+ # String object
15
+ #
16
+ class StringType
17
+ # @!parse include Type
18
+
19
+ extend Forwardable
20
+ include Comparable
21
+ include ComparableType
22
+
23
+ #
24
+ # Check equality without type conversion
25
+ #
26
+ # @return [Boolean] if the same value is represented, without type
27
+ # conversion
28
+ def eql?(other)
29
+ return false unless other.instance_of?(self.class)
30
+
31
+ to_s.compare_to(other.to_s).zero?
32
+ end
33
+
34
+ #
35
+ # Comparison
36
+ #
37
+ # @param [StringType, Items::StringItem, String]
38
+ # other object to compare to
39
+ #
40
+ # @return [Integer, nil] -1, 0, +1 depending on whether +other+ is
41
+ # less than, equal to, or greater than self
42
+ #
43
+ # nil is returned if the two values are incomparable
44
+ #
45
+ def <=>(other) # rubocop:disable Metrics
46
+ logger.trace("(#{self.class}) #{self} <=> #{other} (#{other.class})")
47
+ if other.is_a?(Items::StringItem) ||
48
+ (other.is_a?(Items::GroupItem) && other.base_item.is_a?(StringItem))
49
+ return nil unless other.state?
50
+
51
+ self <=> other.state
52
+ elsif other.respond_to?(:to_str)
53
+ to_str <=> other.to_str
54
+ elsif other.respond_to?(:coerce)
55
+ lhs, rhs = other.coerce(self)
56
+ lhs <=> rhs
57
+ end
58
+ end
59
+
60
+ #
61
+ # Type Coercion
62
+ #
63
+ # Coerce object to a StringType
64
+ #
65
+ # @param [Items::StringItem, String] other object to coerce to a
66
+ # DateTimeType
67
+ #
68
+ # @return [[StringType, StringType]]
69
+ #
70
+ def coerce(other)
71
+ logger.trace("Coercing #{self} as a request from #{other.class}")
72
+ if other.is_a?(Items::StringItem)
73
+ raise TypeError, "can't convert #{other.raw_state} into #{self.class}" unless other.state?
74
+
75
+ [other.state, self]
76
+ elsif other.respond_to?(:to_str)
77
+ [String.new(other.to_str), self]
78
+ else
79
+ raise TypeError, "can't convert #{other.class} into #{self.class}"
80
+ end
81
+ end
82
+
83
+ # any method that exists on String gets forwarded to to_s
84
+ delegate (String.instance_methods - instance_methods) => :to_s
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OpenHAB
4
+ module DSL
5
+ module Types
6
+ java_import org.openhab.core.types.Type
7
+
8
+ #
9
+ # Add basic type conversion and comparison to all core OpenHAB types
10
+ #
11
+ module Type
12
+ # can't alias because to_s doesn't exist on Type
13
+ # @!visibility private
14
+ def inspect
15
+ to_s
16
+ end
17
+
18
+ #
19
+ # Type Coercion
20
+ #
21
+ # Coerce object to the same Type
22
+ #
23
+ # @param [Type] other object to coerce to the same
24
+ # Type as this one
25
+ #
26
+ # @return [[Type, Type]]
27
+ #
28
+ def coerce(other)
29
+ logger.trace("Coercing #{self} (#{self.class}) as a request from #{other.class}")
30
+ return [other.as(self.class), self] if other.is_a?(Type)
31
+
32
+ raise TypeError, "can't convert #{other.class} into #{self.class}"
33
+ end
34
+
35
+ #
36
+ # Check equality without type conversion
37
+ #
38
+ # @return [Boolean] if the same value is represented, without type
39
+ # conversion
40
+ def eql?(other)
41
+ return false unless other.instance_of?(self.class)
42
+
43
+ equals(other)
44
+ end
45
+
46
+ #
47
+ # Check equality, including type conversion
48
+ #
49
+ # @return [Boolean] if the same value is represented, including
50
+ # type conversions
51
+ #
52
+ def ==(other)
53
+ return true if equal?(other)
54
+
55
+ # i.e. ON == OFF, REFRESH == ON, ON == REFRESH
56
+ # (RefreshType isn't really coercible)
57
+ return equals(other) if other.instance_of?(self.class) || is_a?(RefreshType) || other.is_a?(RefreshType)
58
+
59
+ # i.e. ON == DimmerItem (also case statements)
60
+ return self == other.raw_state if other.is_a?(Items::GenericItem)
61
+
62
+ if other.respond_to?(:coerce)
63
+ lhs, rhs = other.coerce(self)
64
+ return lhs == rhs
65
+ end
66
+
67
+ super
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'type'
4
+
5
+ require_relative 'date_time_type'
6
+ require_relative 'decimal_type'
7
+ require_relative 'increase_decrease_type'
8
+ require_relative 'next_previous_type'
9
+ require_relative 'open_closed_type'
10
+ require_relative 'on_off_type'
11
+ require_relative 'percent_type'
12
+ require_relative 'play_pause_type'
13
+ require_relative 'quantity_type'
14
+ require_relative 'refresh_type'
15
+ require_relative 'rewind_fastforward_type'
16
+ require_relative 'stop_move_type'
17
+ require_relative 'string_type'
18
+ require_relative 'up_down_type'
19
+ require_relative 'un_def_type'
20
+
21
+ module OpenHAB
22
+ module DSL
23
+ #
24
+ # Contains all OpenHAB *Type classes, as well as associated support
25
+ # modules
26
+ #
27
+ module Types
28
+ # Hash taking a Enum value, and returning two symbols of
29
+ # predicates to be defined for it. the first is the "command" form,
30
+ # which should be defined on ItemCommandEvent, and on the Type itself.
31
+ # the second is "state" form, which should be defined on the applicable
32
+ # Item, and on the Type itself.
33
+ # @!visibility private
34
+ PREDICATE_ALIASES = Hash.new { |_h, k| [:"#{k.downcase}?"] * 2 }
35
+ .merge({
36
+ 'PLAY' => %i[play? playing?],
37
+ 'PAUSE' => %i[pause? paused?],
38
+ 'REWIND' => %i[rewind? rewinding?],
39
+ 'FASTFORWARD' => %i[fast_forward? fast_forwarding?]
40
+ }).freeze
41
+
42
+ # Hash taking a Enum value, and returning an array of symbols
43
+ # of the command to define for it
44
+ # @!visibility private
45
+ COMMAND_ALIASES = Hash.new { |_h, k| k.downcase.to_sym }
46
+ .merge({
47
+ 'FASTFORWARD' => :fast_forward
48
+ }).freeze
49
+
50
+ constants.map { |c| const_get(c) }
51
+ .grep(Module)
52
+ .select { |k| k < java.lang.Enum }
53
+ .each do |klass|
54
+ # make sure == from Type is inherited
55
+ klass.remove_method(:==)
56
+
57
+ # dynamically define predicate methods
58
+ klass.values.each do |value| # rubocop:disable Style/HashEachMethods this isn't a Ruby hash
59
+ # include all the aliases that we define for items both command and
60
+ # state aliases (since types can be interrogated as an incoming
61
+ # command, or as the state of an item)
62
+ command = :"#{COMMAND_ALIASES[value.to_s]}?"
63
+ states = PREDICATE_ALIASES[value.to_s]
64
+
65
+ ([command] | states).each do |method|
66
+ OpenHAB::Core.logger.trace("Defining #{klass}##{method} for #{value}")
67
+ klass.class_eval <<~RUBY, __FILE__, __LINE__ + 1
68
+ def #{method} # def on?
69
+ self == #{value} # self == ON
70
+ end # end
71
+ RUBY
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end