openhab-jrubyscripting 5.0.0.rc11 → 5.0.0.rc12

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/lib/openhab/core/actions/exec.rb +41 -41
  3. data/lib/openhab/core/items/date_time_item.rb +3 -2
  4. data/lib/openhab/core/items/generic_item.rb +90 -0
  5. data/lib/openhab/core/items/item.rb +9 -8
  6. data/lib/openhab/core/items/metadata/hash.rb +1 -1
  7. data/lib/openhab/core/items/metadata/namespace_hash.rb +10 -2
  8. data/lib/openhab/core/items/metadata/provider.rb +2 -2
  9. data/lib/openhab/core/items/persistence.rb +48 -4
  10. data/lib/openhab/core/items/registry.rb +10 -1
  11. data/lib/openhab/core/items/state_storage.rb +2 -2
  12. data/lib/openhab/core/proxy.rb +5 -0
  13. data/lib/openhab/core/registry.rb +12 -2
  14. data/lib/openhab/core/rules.rb +1 -1
  15. data/lib/openhab/core/things/links/provider.rb +38 -0
  16. data/lib/openhab/core/things/registry.rb +4 -0
  17. data/lib/openhab/core/timer.rb +3 -19
  18. data/lib/openhab/core/types/date_time_type.rb +1 -1
  19. data/lib/openhab/core.rb +3 -3
  20. data/lib/openhab/core_ext/java/duration.rb +2 -0
  21. data/lib/openhab/core_ext/java/local_date.rb +15 -7
  22. data/lib/openhab/core_ext/java/local_time.rb +13 -3
  23. data/lib/openhab/core_ext/java/month.rb +1 -1
  24. data/lib/openhab/core_ext/java/month_day.rb +13 -3
  25. data/lib/openhab/core_ext/java/period.rb +1 -1
  26. data/lib/openhab/core_ext/java/temporal_amount.rb +1 -1
  27. data/lib/openhab/core_ext/java/time.rb +5 -1
  28. data/lib/openhab/core_ext/java/zoned_date_time.rb +15 -2
  29. data/lib/openhab/core_ext/ruby/date.rb +2 -2
  30. data/lib/openhab/core_ext/ruby/numeric.rb +6 -1
  31. data/lib/openhab/dsl/items/builder.rb +25 -12
  32. data/lib/openhab/dsl/rules/automation_rule.rb +2 -23
  33. data/lib/openhab/dsl/rules/builder.rb +47 -2
  34. data/lib/openhab/dsl/version.rb +1 -1
  35. data/lib/openhab/dsl.rb +27 -11
  36. data/lib/openhab/rspec/helpers.rb +3 -2
  37. data/lib/openhab/rspec/hooks.rb +1 -0
  38. data/lib/openhab/rspec/mocks/timer.rb +33 -0
  39. data/lib/openhab/rspec.rb +9 -0
  40. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bc3911eb787dc73ea31109aa6d4d8c3896a1019b381a70030f152c668f0b8f2e
4
- data.tar.gz: ebd2d7005e9f17827a4bf58d38b7fc2476a497cb428aab0270290c3c98461b80
3
+ metadata.gz: 38b109c413cbb8b06c2c43e57ad12e6278139b1cf56d887289ada297c8991272
4
+ data.tar.gz: 24e6235ce553d4e2ec9447c94407054b9c1c075c6a190a3ce5ed5ebb2421753c
5
5
  SHA512:
6
- metadata.gz: df4c1df793cd44700467728c63df6ba9d12ecf7111fc7daf2b9a8f4953c68575082f9f4b87f70a42bfedcc9af70d4537e45b6fb2d8b78ac8e7e3f7cca22aaf4b
7
- data.tar.gz: de1c8f5847bbbeb3eed3268ceedc2a61213b4f6ab269372a08bd4d8217f6b384a2c62b5ceb1f9de2777d264d0d6eb4e02fde6f245fa4fcc0dc03d068041a11bb
6
+ metadata.gz: a3e0f9f2f58d906ff72f5923817a2b5651a96f4710bbd29ad6ecffc3991722db5f8b1702de90e05ef1854ffe49c3d4214a699f271aaf0ac26a2dd03ad20c71f5
7
+ data.tar.gz: a51e80b23b82e7c38db1ac8d263b0a2776a70ad7fe9f401b1ae035f26a06d3660534e4c64c4d1c88a06fb9ee47ef64422b02bdfd26446e8edb148461c1403eca
@@ -4,47 +4,47 @@ module OpenHAB
4
4
  module Core
5
5
  module Actions
6
6
  # @see https://www.openhab.org/docs/configuration/actions.html#exec-actions Exec Actions
7
- class Exec
8
- class << self # rubocop:disable Lint/EmptyClass
9
- # @!method execute_command_line
10
- #
11
- # @return [void]
12
- #
13
- # @overload execute_command_line(command_line)
14
- #
15
- # Executes a command on the command line without waiting for the
16
- # command to complete.
17
- #
18
- # @param [String] command_line
19
- # @return [void]
20
- #
21
- # @example Execute an external command
22
- # rule 'Run a command' do
23
- # every :day
24
- # run do
25
- # Exec.execute_command_line('/bin/true')
26
- # end
27
- # end
28
- #
29
- # @overload execute_command_line(timeout, command_line)
30
- #
31
- # Executes a command on the command and waits timeout seconds for
32
- # the command to complete, returning the output from the command
33
- # as a String.
34
- #
35
- # @param [Duration] timeout
36
- # @param [String] command_line
37
- # @return [String]
38
- #
39
- # @example Execute an external command and process its results
40
- # rule 'Run a command' do
41
- # every :day
42
- # run do
43
- # TodaysHoliday_String.update(Exec.execute_command_line(5.seconds, '/home/cody/determine_holiday.rb')
44
- # end
45
- # end
46
- #
47
- end
7
+ class Exec # rubocop:disable Lint/EmptyClass
8
+ # @!scope class
9
+
10
+ # @!method execute_command_line
11
+ #
12
+ # @return [void]
13
+ #
14
+ # @overload execute_command_line(command_line)
15
+ #
16
+ # Executes a command on the command line without waiting for the
17
+ # command to complete.
18
+ #
19
+ # @param [String] command_line
20
+ # @return [void]
21
+ #
22
+ # @example Execute an external command
23
+ # rule 'Run a command' do
24
+ # every :day
25
+ # run do
26
+ # Exec.execute_command_line('/bin/true')
27
+ # end
28
+ # end
29
+ #
30
+ # @overload execute_command_line(timeout, command_line)
31
+ #
32
+ # Executes a command on the command and waits timeout seconds for
33
+ # the command to complete, returning the output from the command
34
+ # as a String.
35
+ #
36
+ # @param [Duration] timeout
37
+ # @param [String] command_line
38
+ # @return [String]
39
+ #
40
+ # @example Execute an external command and process its results
41
+ # rule 'Run a command' do
42
+ # every :day
43
+ # run do
44
+ # TodaysHoliday_String.update(Exec.execute_command_line(5.seconds, '/home/cody/determine_holiday.rb')
45
+ # end
46
+ # end
47
+ #
48
48
  end
49
49
  end
50
50
  end
@@ -45,9 +45,10 @@ module OpenHAB
45
45
  # Time types need formatted as ISO8601
46
46
  # @!visibility private
47
47
  def format_type(command)
48
- return Types::DateTimeType.new(command) if command.is_a?(java.time.ZonedDateTime)
48
+ return command if command.is_a?(Types::DateTimeType)
49
+ return Types::DateTimeType.new(command.to_zoned_date_time) if command.respond_to?(:to_zoned_date_time)
50
+ return Types::DateTimeType.new(DSL.try_parse_time_like(command.to_str)) if command.respond_to?(:to_str)
49
51
 
50
- command = command.iso8601 if command.respond_to?(:iso8601)
51
52
  super
52
53
  end
53
54
  end
@@ -163,9 +163,99 @@ module OpenHAB
163
163
  # make sure to use Type, because this method is used for both
164
164
  # #update and #command
165
165
  return type if type.is_a?(Types::Type)
166
+ return NULL if type.nil?
166
167
 
167
168
  type.to_s
168
169
  end
170
+
171
+ #
172
+ # Defers notifying openHAB of modifications to multiple attributes until the block is complete.
173
+ #
174
+ # @param [true, false] force When true, allow modifications to file-based items.
175
+ # Normally a FrozenError is raised when attempting to modify file-based items, since
176
+ # they will then be out-of-sync with the definition on disk. Advanced users may do this
177
+ # knowingly and intentionally though, so an escape hatch is provided to allow runtime
178
+ # modifications.
179
+ # @yield
180
+ # @return [Object] the block's return value
181
+ #
182
+ # @example Modify label and tags for an item
183
+ # MySwitch.modify do
184
+ # MySwitch.label = "New Label"
185
+ # MySwitch.tags = :labeled
186
+ # end
187
+ #
188
+ def modify(force: false)
189
+ raise ArgumentError, "you must pass a block to modify" unless block_given?
190
+ return yield if instance_variable_defined?(:@modifying) && @modifying
191
+
192
+ begin
193
+ provider = self.provider
194
+ if provider && !provider.is_a?(org.openhab.core.common.registry.ManagedProvider)
195
+ raise FrozenError, "Cannot modify item #{name} from provider #{provider.inspect}." unless force
196
+
197
+ provider = nil
198
+ logger.debug("Forcing modifications to non-managed item #{name}")
199
+ end
200
+ @modified = false
201
+ @modifying = true
202
+
203
+ r = yield
204
+
205
+ provider&.update(self) if @modified
206
+ r
207
+ ensure
208
+ @modifying = false
209
+ end
210
+ end
211
+
212
+ # @!attribute [rw] label
213
+ # The item's descriptive label.
214
+ # @return [String]
215
+ def label=(value)
216
+ modify do
217
+ next if label == value
218
+
219
+ @modified = true
220
+ set_label(value)
221
+ end
222
+ end
223
+
224
+ # @!attribute [rw] category
225
+ # The item's category.
226
+ # @return [String]
227
+ def category=(value)
228
+ modify do
229
+ value = value&.to_s
230
+ next if category == value
231
+
232
+ @modified = true
233
+ set_category(value)
234
+ end
235
+ end
236
+
237
+ # @!attribute [rw] tags
238
+ # The item's tags
239
+ # @return [Array<String>]
240
+ # @overload tags
241
+ # Returns the item's tags.
242
+ # @return [Array<String>]
243
+ # @overload tags=(values)
244
+ # Sets the item's tags.
245
+ #
246
+ # To remove all tags, assign an empty array or nil.
247
+ # @param [Array<String,Symbol,Semantics::Tag>] values Tags to set.
248
+ # @return [void]
249
+ def tags=(values)
250
+ modify do
251
+ values = DSL::Items::ItemBuilder.normalize_tags(*values)
252
+ next if values.to_set == tags.to_set
253
+
254
+ @modified = true
255
+ remove_all_tags
256
+ add_tags(values)
257
+ end
258
+ end
169
259
  end
170
260
  end
171
261
  end
@@ -24,10 +24,6 @@ module OpenHAB
24
24
  # The item's name.
25
25
  # @return [String]
26
26
 
27
- # @!attribute [r] label
28
- # The item's descriptive label.
29
- # @return [String, nil]
30
-
31
27
  # @!attribute [r] accepted_command_types
32
28
  # @return [Array<Class>] An array of {Command}s that can be sent as commands to this item
33
29
 
@@ -35,7 +31,7 @@ module OpenHAB
35
31
  # @return [Array<Class>] An array of {State}s that can be sent as commands to this item
36
32
 
37
33
  #
38
- # The item's {#label} if one is defined, otherwise it's {#name}.
34
+ # The item's {GenericItem#label label} if one is defined, otherwise its {#name}.
39
35
  #
40
36
  # @return [String]
41
37
  #
@@ -46,7 +42,7 @@ module OpenHAB
46
42
  #
47
43
  # @!attribute [r] groups
48
44
  #
49
- # Return all groups that this item is part of
45
+ # Returns all groups that this item is part of
50
46
  #
51
47
  # @return [Array<Group>] All groups that this item is part of
52
48
  #
@@ -81,7 +77,7 @@ module OpenHAB
81
77
  # @example Access namespace1's configuration
82
78
  # Item1.metadata["namespace1"]["config1"]
83
79
  #
84
- # @example Safely search for the specified value - no errors are raised, only nil returned if a key in the chain doesn"t exist
80
+ # @example Safely search for the specified value - no errors are raised, only nil returned if a key in the chain doesn't exist
85
81
  # Item1.metadata.dig("namespace1", "config1") # => "foo"
86
82
  # Item1.metadata.dig("namespace2", "config1") # => nil
87
83
  #
@@ -189,7 +185,7 @@ module OpenHAB
189
185
  #
190
186
  # @return [Array<Thing>] An array of things or an empty array
191
187
  def things
192
- registry = OSGi.service("org.openhab.core.thing.link.ItemChannelLinkRegistry")
188
+ registry = Things::Links::Provider.registry
193
189
  channels = registry.get_bound_channels(name).to_a
194
190
  channels.map(&:thing_uid).uniq.map { |tuid| EntityLookup.lookup_thing(tuid) }.compact
195
191
  end
@@ -206,6 +202,11 @@ module OpenHAB
206
202
  "#{s}>"
207
203
  end
208
204
 
205
+ # @return [org.openhab.core.common.registry.Provider]
206
+ def provider
207
+ Provider.registry.provider_for(self)
208
+ end
209
+
209
210
  private
210
211
 
211
212
  # Allows sub-classes to append additional details to the type in an inspect string
@@ -384,7 +384,7 @@ module OpenHAB
384
384
  alias_method :to_s, :inspect
385
385
 
386
386
  #
387
- # @raise [RuntimeError] if the provider is not a
387
+ # @raise [FrozenError] if the provider is not a
388
388
  # {org.openhab.core.common.registry.ManagedProvider ManagedProvider} that can be updated.
389
389
  # @return [org.openhab.core.common.registry.ManagedProvider]
390
390
  #
@@ -218,8 +218,12 @@ module OpenHAB
218
218
  return @hash.each_key(&block) unless attached?
219
219
  return to_enum(:each_key) unless block
220
220
 
221
- Provider.registry.all.each do |meta|
222
- yield meta.uid.namespace if meta.uid.item_name == @item_name
221
+ if Provider.registry.respond_to?(:get_all_namespaces)
222
+ keys.each(&block)
223
+ else
224
+ Provider.registry.all.each do |meta|
225
+ yield meta.uid.namespace if meta.uid.item_name == @item_name
226
+ end
223
227
  end
224
228
  self
225
229
  end
@@ -313,6 +317,10 @@ module OpenHAB
313
317
 
314
318
  # @!visibility private
315
319
  def keys
320
+ if Provider.registry.respond_to?(:get_all_namespaces)
321
+ return Provider.registry.get_all_namespaces(@item_name).to_a
322
+ end
323
+
316
324
  each_key.to_a
317
325
  end
318
326
 
@@ -32,8 +32,8 @@ module OpenHAB
32
32
  # @return [void]
33
33
  #
34
34
  def remove_item_metadata(item_name)
35
- @elements.delete_if do |k, v|
36
- next unless k.item_name == item_name
35
+ @elements.delete_if do |_k, v|
36
+ next unless v.uid.item_name == item_name
37
37
 
38
38
  notify_listeners_about_removed_element(v)
39
39
  true
@@ -77,7 +77,6 @@ module OpenHAB
77
77
  %i[changed_since?
78
78
  count_since
79
79
  count_state_changes_since
80
- evolution_rate
81
80
  historic_state
82
81
  maximum_since
83
82
  minimum_since
@@ -183,11 +182,22 @@ module OpenHAB
183
182
  # @return [true,false] True if the item's state changed between `start` and `finish`, False otherwise.
184
183
 
185
184
  # @!method evolution_rate(timestamp, service = nil)
186
- # Returns the evolution rate of the item's state since the given time
187
- # @param [#to_zoned_date_time] timestamp The point in time from which to search
188
- # @param [Symbol, String] service An optional persistence id instead of the default persistence service.
185
+ # Returns the evolution rate of the item's state
189
186
  # @return [DecimalType, QuantityType, nil] The evolution rate since `timestamp`,
190
187
  # or nil if no previous state could be found.
188
+ # @overload evolution_rate(timestamp, service = nil)
189
+ # Returns the evolution rate of the item's state since the given time
190
+ # @param [#to_zoned_date_time] timestamp The point in time from which to search
191
+ # @param [Symbol, String] service An optional persistence id instead of the default persistence service.
192
+ # @return [DecimalType, QuantityType, nil] The evolution rate since `timestamp`,
193
+ # or nil if no previous state could be found.
194
+ # @overload evolution_rate(start, finish, service = nil)
195
+ # Returns the evolution rate of the item's state between two points in time
196
+ # @param [#to_zoned_date_time] start The point in time from which to search
197
+ # @param [#to_zoned_date_time] finish The point in time to which to search
198
+ # @param [Symbol, String] service An optional persistence id instead of the default persistence service.
199
+ # @return [DecimalType, QuantityType, nil] The evolution rate between `start` and `finish`,
200
+ # or nil if no previous state could be found.
191
201
 
192
202
  # @!method historic_state(timestamp, service = nil)
193
203
  # Returns the the item's state at the given time
@@ -317,6 +327,40 @@ module OpenHAB
317
327
  end
318
328
  end
319
329
 
330
+ # evolution_rate's "between" method is overloaded with the same name
331
+ method = :evolution_rate
332
+ define_method(method) do |start, finish_or_service = nil, service = nil|
333
+ if service.nil?
334
+ if finish_or_service.respond_to?(:to_zoned_date_time)
335
+ service = persistence_service
336
+ finish = finish_or_service
337
+ else
338
+ service = finish_or_service || persistence_service
339
+ finish = nil
340
+ end
341
+ else
342
+ finish = finish_or_service
343
+ end
344
+
345
+ result = if finish
346
+ Actions::PersistenceExtensions.public_send(
347
+ method,
348
+ self,
349
+ start.to_zoned_date_time,
350
+ finish.to_zoned_date_time,
351
+ service&.to_s
352
+ )
353
+ else
354
+ Actions::PersistenceExtensions.public_send(
355
+ method,
356
+ self,
357
+ start.to_zoned_date_time,
358
+ service&.to_s
359
+ )
360
+ end
361
+ wrap_result(result, method)
362
+ end
363
+
320
364
  alias_method :state_changes_since, :count_state_changes_since
321
365
  alias_method :state_changes_between, :count_state_changes_between
322
366
 
@@ -59,16 +59,25 @@ module OpenHAB
59
59
  #
60
60
  # The item must be a managed item (typically created by Ruby or in the UI).
61
61
  #
62
+ # Any associated metadata or channel links are also removed.
63
+ #
62
64
  # @param [String, Item] item_name
63
65
  # @param recursive [true, false] Remove the item's members if it's a group
64
66
  # @return [Item, nil] The removed item, if found.
65
67
  def remove(item_name, recursive: false)
66
68
  item_name = item_name.name if item_name.is_a?(Item)
67
69
  provider = Provider.registry.provider_for(item_name)
68
- unless provider.is_a?(org.openhab.core.common.registry.ManagedProvider)
70
+ unless provider.is_a?(ManagedProvider)
69
71
  raise "Cannot remove item #{item_name} from non-managed provider #{provider.inspect}"
70
72
  end
71
73
 
74
+ Metadata::Provider.registry.providers.grep(ManagedProvider).each do |managed_provider|
75
+ managed_provider.remove_item_metadata(item_name)
76
+ end
77
+
78
+ Things::Links::Provider.registry.providers.grep(ManagedProvider).each do |managed_provider|
79
+ managed_provider.remove_links_for_item(item_name)
80
+ end
72
81
  provider.remove(item_name, recursive)
73
82
  end
74
83
  end
@@ -12,13 +12,13 @@ module OpenHAB
12
12
  #
13
13
  # Create a StateStorage object that stores the states of the given items
14
14
  #
15
- # @param [Array<Item>] items A list of items
15
+ # @param [Item] items A list of items
16
16
  #
17
17
  # @return [StateStorage] A state storage object
18
18
  #
19
19
  # @!visibility private
20
20
  def self.from_items(*items)
21
- StateStorage.new($events.store_states(*items).to_h)
21
+ StateStorage.new($events.store_states(*items.map(&:to_java)).to_h)
22
22
  end
23
23
 
24
24
  #
@@ -120,6 +120,11 @@ module OpenHAB
120
120
  # define a sub-class of EventSubscriber as a child class of the including class
121
121
  klass.const_set(:EventSubscriber, Class.new(EventSubscriber))
122
122
  end
123
+
124
+ # @!visibility private
125
+ def to_java
126
+ __getobj__
127
+ end
123
128
  end
124
129
  end
125
130
  end
@@ -4,7 +4,7 @@ module OpenHAB
4
4
  module Core
5
5
  Registry = org.openhab.core.common.registry.AbstractRegistry
6
6
 
7
- Registry.field_reader :elementToProvider, :elementReadLock, :identifierToElement
7
+ Registry.field_reader :elementToProvider, :elementReadLock, :identifierToElement, :providerToElements
8
8
 
9
9
  # @abstract
10
10
  #
@@ -19,12 +19,22 @@ module OpenHAB
19
19
  #
20
20
  def provider_for(key)
21
21
  elementReadLock.lock
22
- return nil unless (element = identifierToElement[key])
22
+ if key.is_a?(org.openhab.core.common.registry.Identifiable)
23
+ element = key
24
+ else
25
+ return nil unless (element = identifierToElement[key])
26
+ end
23
27
 
24
28
  elementToProvider[element]
25
29
  ensure
26
30
  elementReadLock.unlock
27
31
  end
32
+
33
+ # @!attribute [r] providers
34
+ # @return [Enumerable<org.openhab.core.common.registry.Provider>]
35
+ def providers
36
+ providerToElements.keys
37
+ end
28
38
  end
29
39
  end
30
40
  end
@@ -13,7 +13,7 @@ module OpenHAB
13
13
 
14
14
  class << self
15
15
  #
16
- # @!attribute [r] rule_manager
16
+ # @!attribute [r] manager
17
17
  # @return [org.openhab.core.automation.RuleManager] The openHAB rule manager/engine
18
18
  #
19
19
  def manager
@@ -33,6 +33,44 @@ module OpenHAB
33
33
  current.add(link)
34
34
  end
35
35
  end
36
+
37
+ #
38
+ # Removes all links to a given item.
39
+ #
40
+ # @param [String] item_name
41
+ # @return [Integer] how many links were removed
42
+ #
43
+ def remove_links_for_item(item_name)
44
+ count = 0
45
+ @elements.delete_if do |_k, v|
46
+ next unless v.item_name == item_name
47
+
48
+ count += 1
49
+ notify_listeners_about_removed_element(v)
50
+ true
51
+ end
52
+ count
53
+ end
54
+ alias_method :removeLinksForItem, :remove_links_for_item
55
+
56
+ #
57
+ # Removes all links to a given thing.
58
+ #
59
+ # @param [ThingUID] thing_uid
60
+ # @return [Integer] how many links were removed
61
+ #
62
+ def remove_links_for_thing(thing_uid)
63
+ count = 0
64
+ @elements.delete_if do |_k, v|
65
+ next unless v.linked_uid.thing_uid == thing_uid
66
+
67
+ count += 1
68
+ notify_listeners_about_removed_element(v)
69
+ true
70
+ end
71
+ count
72
+ end
73
+ alias_method :removeLinksForThing, :remove_links_for_thing
36
74
  end
37
75
  end
38
76
  end
@@ -61,6 +61,10 @@ module OpenHAB
61
61
  raise "Cannot remove thing #{thing_uid} from non-managed provider #{provider.inspect}"
62
62
  end
63
63
 
64
+ Links::Provider.registry.providers.grep(ManagedProvider).each do |managed_provider|
65
+ managed_provider.remove_links_for_thing(thing_uid)
66
+ end
67
+
64
68
  provider.remove(thing_uid)
65
69
  end
66
70
  end
@@ -28,7 +28,7 @@ module OpenHAB
28
28
  # @return [true,false]
29
29
 
30
30
  def_delegator :@timer, :has_terminated, :terminated?
31
- def_delegators :@timer, :active?, :cancelled?, :running?
31
+ def_delegators :@timer, :active?, :cancelled?, :running?, :execution_time
32
32
 
33
33
  # @return [Object, nil]
34
34
  attr_accessor :id
@@ -49,19 +49,7 @@ module OpenHAB
49
49
  @id = id
50
50
  @thread_locals = thread_locals
51
51
  @block = block
52
- @timer = if defined?(ScriptExecution)
53
- ScriptExecution.create_timer(1.minute.from_now) { execute }
54
- else # DEPRECATED: openHAB 3.4.0
55
- org.openhab.core.model.script.actions.ScriptExecution.create_timer(
56
- # create it far enough in the future so it won't execute until we finish setting it up
57
- 1.minute.from_now,
58
- # when running in rspec, it may have troubles finding this class
59
- # for auto-conversion of block to interface, so use .impl
60
- org.eclipse.xtext.xbase.lib.Procedures::Procedure0.impl { execute }
61
- )
62
- end
63
- # DEPRECATED: openHAB 3.4.0.M6
64
- @timer.class.field_reader :future unless @timer.respond_to?(:future)
52
+ @timer = ScriptExecution.create_timer(1.minute.from_now) { execute }
65
53
  reschedule(@time)
66
54
  end
67
55
 
@@ -79,11 +67,7 @@ module OpenHAB
79
67
  alias_method :to_s, :inspect
80
68
 
81
69
  # @!attribute [r] execution_time
82
- # @return [ZonedDateTime, nil] the scheduled execution time, or `nil` if the timer was cancelled
83
- def execution_time
84
- # DEPRECATED: openHAB 3.4.0.M6 (just remove the entire method)
85
- @timer.future.scheduled_time
86
- end
70
+ # @return [ZonedDateTime, nil] the scheduled execution time, or `nil` if the timer was cancelled
87
71
 
88
72
  #
89
73
  # Reschedule timer
@@ -46,7 +46,7 @@ module OpenHAB
46
46
  rescue java.lang.StringIndexOutOfBoundsException, java.lang.IllegalArgumentException => e
47
47
  # Try Ruby's Time.parse if DateTimeType parser fails
48
48
  begin
49
- ::Time.parse(time_string).to_zoned_date_time
49
+ DateTimeType.new(::Time.parse(time_string).to_zoned_date_time)
50
50
  rescue ArgumentError
51
51
  raise ArgumentError, e.message
52
52
  end
data/lib/openhab/core.rb CHANGED
@@ -3,12 +3,12 @@
3
3
  module OpenHAB
4
4
  # Contains classes and modules that wrap actual openHAB objects
5
5
  module Core
6
- # The openHAB Version. >= 3.3.0 is required.
6
+ # The openHAB Version. >= 3.4.0 is required.
7
7
  # @return [String]
8
8
  VERSION = org.openhab.core.OpenHAB.version.freeze
9
9
 
10
- unless Gem::Version.new(VERSION) >= Gem::Version.new("3.3.0")
11
- raise "`openhab-jrubyscripting` requires openHAB >= 3.3.0"
10
+ unless Gem::Version.new(VERSION) >= Gem::Version.new("3.4.0")
11
+ raise "`openhab-jrubyscripting` requires openHAB >= 3.4.0"
12
12
  end
13
13
 
14
14
  # @return [Integer] Number of seconds to wait between checks for automation manager
@@ -52,6 +52,8 @@ module OpenHAB
52
52
  return to_f <=> other if other.is_a?(Numeric)
53
53
 
54
54
  super
55
+ rescue TypeError
56
+ nil
55
57
  end
56
58
 
57
59
  #
@@ -7,16 +7,24 @@ module OpenHAB
7
7
  module Java
8
8
  java_import java.time.LocalDate
9
9
 
10
- # Extensions to LocalDate
10
+ # Extensions to {java.time.LocalDate}
11
11
  class LocalDate
12
12
  include Time
13
13
  include Between
14
14
  include Ephemeris
15
15
 
16
- class << self # rubocop:disable Lint/EmptyClass
17
- # @!attribute [r] now
18
- # @return [ZonedDateTime]
19
- end
16
+ # @!scope class
17
+
18
+ # @!attribute [r] now
19
+ # @return [LocalDate]
20
+
21
+ # @!method parse(text, formatter=nil)
22
+ # Converts the given text into a LocalDate.
23
+ # @param [String] text The text to parse
24
+ # @param [java.time.format.DateTimeFormatter] formatter The formatter to use
25
+ # @return [LocalDate]
26
+
27
+ # @!scope instance
20
28
 
21
29
  # @param [TemporalAmount, LocalDate, Numeric] other
22
30
  # If other is a Numeric, it's interpreted as days.
@@ -25,11 +33,11 @@ module OpenHAB
25
33
  def -(other)
26
34
  case other
27
35
  when Date
28
- Period.of_days(day_of_year - other.yday)
36
+ self - other.to_local_date
29
37
  when MonthDay
30
38
  self - other.at_year(year)
31
39
  when LocalDate
32
- Period.of_days(day_of_year - other.day_of_year)
40
+ Period.between(other, self)
33
41
  when Duration
34
42
  minus_days(other.to_days)
35
43
  when Numeric
@@ -7,6 +7,8 @@ module OpenHAB
7
7
  module Java
8
8
  java_import java.time.LocalTime
9
9
 
10
+ #
11
+ # Extensions to {java.time.LocalTime}
10
12
  #
11
13
  # @example
12
14
  # break_time = LocalTime::NOON
@@ -36,15 +38,23 @@ module OpenHAB
36
38
  include Between
37
39
  # @!parse include Time
38
40
 
39
- # @!visibility private
40
41
  class << self
42
+ # @!attribute [r] now
43
+ # @return [LocalTime]
44
+
45
+ # @!visibility private
46
+ alias_method :raw_parse, :parse
47
+
41
48
  #
42
- # Parses strings in the form "h[:mm[:ss]] [am/pm]"
49
+ # Parses strings in the form "h[:mm[:ss]] [am/pm]" when no formatter is given.
43
50
  #
44
51
  # @param [String] string
52
+ # @param [java.time.format.DateTimeFormatter] formatter The formatter to use
45
53
  # @return [LocalTime]
46
54
  #
47
- def parse(string)
55
+ def parse(string, formatter = nil)
56
+ return raw_parse(string, formatter) if formatter
57
+
48
58
  format = /(am|pm)$/i.match?(string) ? "h[:mm[:ss][.S]][ ]a" : "H[:mm[:ss][.S]]"
49
59
  java_send(:parse, [java.lang.CharSequence, java.time.format.DateTimeFormatter],
50
60
  string, java.time.format.DateTimeFormatterBuilder.new
@@ -7,7 +7,7 @@ module OpenHAB
7
7
  module Java
8
8
  Month = java.time.Month
9
9
 
10
- # Extensions to Month
10
+ # Extensions to {java.time.Month}
11
11
  class Month
12
12
  include Between
13
13
  # @!parse include Time
@@ -7,7 +7,7 @@ module OpenHAB
7
7
  module Java
8
8
  java_import java.time.MonthDay
9
9
 
10
- # Extensions to MonthDay
10
+ # Extensions to {java.time.MonthDay}
11
11
  class MonthDay
12
12
  include Between
13
13
  include Ephemeris
@@ -39,12 +39,22 @@ module OpenHAB
39
39
 
40
40
  # @return [MonthDay]
41
41
  def +(other)
42
- (LocalDate.of(1900, month, day_of_month) + other).to_month_day
42
+ case other
43
+ when java.time.temporal.TemporalAmount, Numeric
44
+ (LocalDate.of(1900, month, day_of_month) + other).to_month_day
45
+ else
46
+ (to_local_date(other.to_local_date) + other).to_month_day
47
+ end
43
48
  end
44
49
 
45
50
  # @return [MonthDay, Period]
46
51
  def -(other)
47
- d = (LocalDate.of(1900, month, day_of_month) - other)
52
+ d = case other
53
+ when java.time.temporal.TemporalAmount, Numeric
54
+ LocalDate.of(1900, month, day_of_month) - other
55
+ else
56
+ to_local_date(other.to_local_date) - other
57
+ end
48
58
  return d if d.is_a?(java.time.Period)
49
59
 
50
60
  d.to_month_day
@@ -5,7 +5,7 @@ module OpenHAB
5
5
  module Java
6
6
  java_import java.time.Period
7
7
 
8
- # Extensions to Period
8
+ # Extensions to {java.time.Period}
9
9
  class Period
10
10
  # @!parse include TemporalAmount
11
11
 
@@ -5,7 +5,7 @@ module OpenHAB
5
5
  module Java
6
6
  java_import java.time.temporal.TemporalAmount
7
7
 
8
- # Extensions to TemporalAmount
8
+ # Extensions to {java.time.temporal.TemporalAmount}
9
9
  module TemporalAmount
10
10
  # Subtract `self` to {ZonedDateTime.now}
11
11
  # @return [ZonedDateTime]
@@ -50,7 +50,11 @@ module OpenHAB
50
50
  # Convert `other` to this class, if possible
51
51
  # @return [Array, nil]
52
52
  def coerce(other)
53
- [other.send(self.class.coercion_method), self] if other.respond_to?(self.class.coercion_method)
53
+ coercion_method = self.class.coercion_method
54
+ return unless other.respond_to?(coercion_method)
55
+ return [other.send(coercion_method), self] if other.method(coercion_method).arity.zero?
56
+
57
+ [other.send(coercion_method, self), self]
54
58
  end
55
59
  end
56
60
  end
@@ -7,18 +7,31 @@ module OpenHAB
7
7
  module Java
8
8
  ZonedDateTime = java.time.ZonedDateTime
9
9
 
10
- # Extensions to ZonedDateTime
10
+ # Extensions to {java.time.ZonedDateTime}
11
11
  class ZonedDateTime
12
12
  include Time
13
13
  include Between
14
14
 
15
15
  class << self # rubocop:disable Lint/EmptyClass
16
+ # @!scope class
17
+
16
18
  # @!attribute [r] now
17
19
  # @return [ZonedDateTime]
20
+
21
+ # @!method parse(text, formatter = nil)
22
+ # Parses a string into a ZonedDateTime object.
23
+ #
24
+ # @param [String] text The text to parse.
25
+ # @param [java.time.format.DateTimeFormatter] formatter The formatter to use.
26
+ # @return [ZonedDateTime]
18
27
  end
19
28
 
29
+ # @!scope instance
30
+
20
31
  # @return [LocalTime]
21
- alias_method :to_local_time, :toLocalTime
32
+ def to_local_time(_context = nil)
33
+ toLocalTime
34
+ end
22
35
 
23
36
  # @return [Month]
24
37
  alias_method :to_month, :month
@@ -85,9 +85,9 @@ class Date
85
85
  #
86
86
  def coerce(other)
87
87
  return nil unless other.respond_to?(:to_date)
88
- return [other.to_date(self), self] if other.method(:to_date).arity == 1
88
+ return [other.to_date, self] if other.method(:to_date).arity.zero?
89
89
 
90
- [other.to_date, self]
90
+ [other.to_date(self), self]
91
91
  end
92
92
 
93
93
  remove_method :inspect
@@ -151,7 +151,12 @@ module OpenHAB
151
151
  # @return [QuantityType] `self` as a {QuantityType} of the supplied Unit
152
152
  #
153
153
  def |(unit) # rubocop:disable Naming/BinaryOperatorParameterName
154
- unit = org.openhab.core.types.util.UnitUtils.parse_unit(unit.to_str) if unit.respond_to?(:to_str)
154
+ if unit.respond_to?(:to_str)
155
+ parsed_unit = org.openhab.core.types.util.UnitUtils.parse_unit(unit.to_str)
156
+ raise ArgumentError, "Unknown unit #{unit}" unless parsed_unit
157
+
158
+ unit = parsed_unit
159
+ end
155
160
 
156
161
  return super unless unit.is_a?(javax.measure.Unit)
157
162
 
@@ -187,6 +187,30 @@ module OpenHAB
187
187
  def item_factory
188
188
  @item_factory ||= org.openhab.core.library.CoreItemFactory.new
189
189
  end
190
+
191
+ #
192
+ # Convert the given array to an array of strings.
193
+ # Convert Semantics classes to their simple name.
194
+ #
195
+ # @param [String,Symbol,Semantics::Tag] tags A list of strings, symbols, or Semantics classes
196
+ # @return [Array] An array of strings
197
+ #
198
+ # @example
199
+ # tags = normalize_tags("tag1", Semantics::LivingRoom)
200
+ #
201
+ # @!visibility private
202
+ def normalize_tags(*tags)
203
+ semantics = proc { |tag| tag.respond_to?(:java_class) && tag < Semantics::Tag }
204
+
205
+ tags.compact.map do |tag|
206
+ case tag
207
+ when String then tag
208
+ when Symbol then tag.to_s
209
+ when semantics then tag.java_class.simple_name
210
+ else raise ArgumentError, "`#{tag}` must be a subclass of Semantics::Tag, a `Symbol`, or a `String`."
211
+ end
212
+ end
213
+ end
190
214
  end
191
215
 
192
216
  # @param dimension [Symbol, nil] The unit dimension for a {NumberItem} (see {ItemBuilder#dimension})
@@ -294,18 +318,7 @@ module OpenHAB
294
318
  # @return [void]
295
319
  #
296
320
  def tag(*tags)
297
- unless tags.all? do |tag|
298
- tag.is_a?(String) ||
299
- tag.is_a?(Symbol) ||
300
- (tag.is_a?(Module) && tag < Semantics::Tag)
301
- end
302
- raise ArgumentError, "`tag` must be a subclass of Semantics::Tag, or a `String``."
303
- end
304
-
305
- tags.each do |tag|
306
- tag = tag.name.split("::").last if tag.is_a?(Module) && tag < Semantics::Tag
307
- @tags << tag.to_s
308
- end
321
+ @tags += self.class.normalize_tags(*tags)
309
322
  end
310
323
 
311
324
  #
@@ -35,7 +35,8 @@ module OpenHAB
35
35
  super()
36
36
  set_name(config.name)
37
37
  set_description(config.description)
38
- set_tags(to_string_set(config.tags))
38
+ tags = DSL::Items::ItemBuilder.normalize_tags(*config.tags)
39
+ set_tags(tags.to_set)
39
40
  set_triggers(config.triggers)
40
41
  self.uid = config.uid
41
42
  @run_context = config.caller
@@ -297,28 +298,6 @@ module OpenHAB
297
298
  @run_context.instance_exec(&task.block)
298
299
  end
299
300
 
300
- #
301
- # Convert the given array to a set of strings.
302
- # Convert Semantics classes to their simple name
303
- #
304
- # @example
305
- # to_string_set("tag1", Semantics::LivingRoom)
306
- #
307
- # @param tags [Array] An array of strings or Semantics classes
308
- #
309
- # @return [Set] A set of strings
310
- #
311
- def to_string_set(*tags)
312
- tags = tags.flatten.map do |tag|
313
- if tag.respond_to?(:java_class) && tag < org.openhab.core.semantics.Tag
314
- tag.java_class.simple_name
315
- else
316
- tag.to_s
317
- end
318
- end
319
- Set.new(tags)
320
- end
321
-
322
301
  #
323
302
  # Create a new hash in which all elements are converted to strings
324
303
  #
@@ -358,7 +358,7 @@ module OpenHAB
358
358
  #
359
359
  # Set the rule's tags.
360
360
  #
361
- # @param [String, Class, Array<String, Class>] tags
361
+ # @param [String, Symbol, Semantics::Tag] tags A list of tags to assign to the rule.
362
362
  # @return [void]
363
363
  #
364
364
  # @example
@@ -1101,7 +1101,10 @@ module OpenHAB
1101
1101
  # :saturday,
1102
1102
  # :sunday] value
1103
1103
  # When to execute rule.
1104
- # @param [LocalTime, String, nil] at What time of day to execute rule
1104
+ # @param [LocalTime, String, Core::Items::DateTimeItem, nil] at What time of day to execute rule
1105
+ # If `value` is `:day`, `at` can be a {Core::Items::DateTimeItem DateTimeItem}, and
1106
+ # the trigger will run every day at the (time only portion of) current state of the
1107
+ # item. If the item is {NULL} or {UNDEF}, the trigger will not run.
1105
1108
  # @param [Object] attach Object to be attached to the trigger
1106
1109
  # @return [void]
1107
1110
  #
@@ -1157,11 +1160,23 @@ module OpenHAB
1157
1160
  # run { logger.info "Happy Valentine's Day!" }
1158
1161
  # end
1159
1162
  #
1163
+ # @example
1164
+ # rule "Every day at sunset" do
1165
+ # every :day, at: Sunset_Time
1166
+ # run { logger.info "It's getting dark" }
1167
+ # end
1168
+ #
1160
1169
  def every(value, at: nil, attach: nil)
1161
1170
  return every(java.time.MonthDay.parse(value), at: at, attach: attach) if value.is_a?(String)
1162
1171
 
1163
1172
  @ruby_triggers << [:every, value, { at: at }]
1164
1173
 
1174
+ if value == :day && at.is_a?(Item)
1175
+ raise ArgumentError, "Attachments are not supported with dynamic datetime triggers" unless attach.nil?
1176
+
1177
+ return trigger("timer.DateTimeTrigger", itemName: at.name, timeOnly: true)
1178
+ end
1179
+
1165
1180
  cron_expression = case value
1166
1181
  when Symbol then Cron.from_symbol(value, at)
1167
1182
  when Duration then Cron.from_duration(value, at)
@@ -1502,6 +1517,36 @@ module OpenHAB
1502
1517
  trigger("core.GenericEventTrigger", eventTopic: topic, eventSource: source, eventTypes: types, attach: attach)
1503
1518
  end
1504
1519
 
1520
+ #
1521
+ # Creates a trigger based on the time stored in a {DateTimeItem}
1522
+ #
1523
+ # The trigger will dynamically update any time the state of the item
1524
+ # changes. If the item is {NULL} or {UNDEF}, the trigger will not run.
1525
+ #
1526
+ # @param [Item, String, Symbol] item The item (or it's name)
1527
+ # @return [void]
1528
+ #
1529
+ # @example
1530
+ # rule "say hello when the kids get home from school" do
1531
+ # at HomeFromSchool_Time
1532
+ # run do
1533
+ # KitchenEcho_TTS << "hi kids! how was school?"
1534
+ # end
1535
+ # end
1536
+ #
1537
+ # rule "set home from school time" do
1538
+ # on_load
1539
+ # every :day, at: "5:00am" do
1540
+ # run do
1541
+ # HomeFromSchool_Time.ensure.update(school_day? ? LocalTime.parse("3:30pm") : NULL)
1542
+ # end
1543
+ # end
1544
+ #
1545
+ def at(item)
1546
+ item = item.name if item.is_a?(Item)
1547
+ trigger("timer.DateTimeTrigger", itemName: item.to_s)
1548
+ end
1549
+
1505
1550
  #
1506
1551
  # Create a generic trigger given the trigger type uid and a configuration hash
1507
1552
  #
@@ -4,6 +4,6 @@ module OpenHAB
4
4
  module DSL
5
5
  # Version of openHAB helper libraries
6
6
  # @return [String]
7
- VERSION = "5.0.0.rc11"
7
+ VERSION = "5.0.0.rc12"
8
8
  end
9
9
  end
data/lib/openhab/dsl.rb CHANGED
@@ -152,8 +152,6 @@ module OpenHAB
152
152
  #
153
153
  # @see Core::ValueCache ValueCache
154
154
  #
155
- # @since openHAB 3.4.0
156
- #
157
155
  def shared_cache
158
156
  $sharedCache
159
157
  end
@@ -523,9 +521,6 @@ module OpenHAB
523
521
  # end # the states will be restored here
524
522
  #
525
523
  def store_states(*items)
526
- items = items.flatten.map do |item|
527
- item.respond_to?(:__getobj__) ? item.__getobj__ : item
528
- end
529
524
  states = Core::Items::StateStorage.from_items(*items)
530
525
  if block_given?
531
526
  yield
@@ -604,18 +599,39 @@ module OpenHAB
604
599
  # Item1.average_since(12.hours)
605
600
  # end
606
601
  #
607
- # @see OpenHAB::Core::Items::Persistence
608
- #
609
- # @param [Object] service service either as a String or a Symbol
602
+ # @param [Object] service Persistence service either as a String or a Symbol
610
603
  # @yield [] Block executed in context of the supplied persistence service
611
604
  # @return [Object] The return value from the block.
612
605
  #
606
+ # @see persistence!
607
+ # @see OpenHAB::Core::Items::Persistence
608
+ #
613
609
  def persistence(service)
614
- old = Thread.current[:openhab_persistence_service]
615
- Thread.current[:openhab_persistence_service] = service
610
+ old = persistence!(service)
616
611
  yield
617
612
  ensure
618
- Thread.current[:openhab_persistence_service] = old
613
+ persistence!(old)
614
+ end
615
+
616
+ #
617
+ # Permanently sets the default persistence service for the current thread
618
+ #
619
+ # @note This method is only intended for use at the top level of rule
620
+ # scripts. If it's used within library methods, or hap-hazardly within
621
+ # rules, things can get very confusing because the prior state won't be
622
+ # properly restored.
623
+ #
624
+ # @param [Object] service Persistence service either as a String or a Symbol. When nil, use
625
+ # the system's default persistence service.
626
+ # @return [Object,nil] The previous persistence service settings, or nil when using the system's default.
627
+ #
628
+ # @see persistence
629
+ # @see OpenHAB::Core::Items::Persistence
630
+ #
631
+ def persistence!(service = nil)
632
+ old = Thread.current[:openhab_persistence_service]
633
+ Thread.current[:openhab_persistence_service] = service
634
+ old
619
635
  end
620
636
 
621
637
  #
@@ -265,12 +265,13 @@ module OpenHAB
265
265
  # @return [void]
266
266
  #
267
267
  def load_rules
268
- automation_path = "#{org.openhab.core.OpenHAB.config_folder}/automation/ruby"
268
+ automation_paths = Array(::RSpec.configuration.openhab_automation_search_paths)
269
+
269
270
  lib_dirs = rubylib_dirs.map { |d| File.join(d, "") }
270
271
  lib_dirs << File.join(gem_home, "")
271
272
 
272
273
  SuspendRules.suspend_rules do
273
- files = Dir["#{automation_path}/**/*.rb"]
274
+ files = automation_paths.map { |p| Dir["#{p}/**/*.rb"] }.flatten
274
275
  files.reject! do |f|
275
276
  lib_dirs.any? { |l| f.start_with?(l) }
276
277
  end
@@ -100,6 +100,7 @@ module OpenHAB
100
100
  restore_autoupdate_items
101
101
  Mocks::PersistenceService.instance.reset
102
102
  Hooks.cache_script_extension.sharedCache.clear if DSL.shared_cache
103
+ DSL.persistence!(nil)
103
104
  end
104
105
  end
105
106
  end
@@ -17,6 +17,39 @@ module OpenHAB
17
17
  end
18
18
  ZonedDateTime.singleton_class.prepend(MockedZonedDateTime)
19
19
 
20
+ # @!visibility private
21
+ module MockedLocalDate
22
+ def now
23
+ mocked_time_stack_item = Timecop.top_stack_item
24
+ return super unless mocked_time_stack_item
25
+
26
+ mocked_time_stack_item.time.to_zoned_date_time.to_local_date
27
+ end
28
+ end
29
+ LocalDate.singleton_class.prepend(MockedLocalDate)
30
+
31
+ # @!visibility private
32
+ module MockedLocalTime
33
+ def now
34
+ mocked_time_stack_item = Timecop.top_stack_item
35
+ return super unless mocked_time_stack_item
36
+
37
+ mocked_time_stack_item.time.to_zoned_date_time.to_local_time
38
+ end
39
+ end
40
+ LocalTime.singleton_class.prepend(MockedLocalTime)
41
+
42
+ # @!visibility private
43
+ module MockedMonthDay
44
+ def now
45
+ mocked_time_stack_item = Timecop.top_stack_item
46
+ return super unless mocked_time_stack_item
47
+
48
+ mocked_time_stack_item.time.to_zoned_date_time.to_month_day
49
+ end
50
+ end
51
+ MonthDay.singleton_class.prepend(MockedMonthDay)
52
+
20
53
  # extend Timecop to support Java time classes
21
54
  # @!visibility private
22
55
  module TimeCopStackItem
data/lib/openhab/rspec.rb CHANGED
@@ -15,3 +15,12 @@ require_relative "rspec/configuration"
15
15
  require_relative "rspec/helpers"
16
16
  require_relative "rspec/karaf"
17
17
  require_relative "rspec/hooks"
18
+
19
+ return unless defined?(RSpec)
20
+
21
+ RSpec.configure do |c|
22
+ c.add_setting :openhab_automation_search_paths, default: [
23
+ "#{org.openhab.core.OpenHAB.config_folder}/automation/ruby",
24
+ "#{org.openhab.core.OpenHAB.config_folder}/automation/jsr223"
25
+ ]
26
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: openhab-jrubyscripting
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.0.0.rc11
4
+ version: 5.0.0.rc12
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cody Cutrer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-12-25 00:00:00.000000000 Z
11
+ date: 2023-01-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler