openhab-scripting 4.1.4 → 4.2.0

Sign up to get free protection for your applications and to get access to all the features.
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