openhab-scripting 2.9.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (113) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/workflow.yml +327 -0
  3. data/.gitignore +17 -0
  4. data/.java-version +1 -0
  5. data/.rspec +1 -0
  6. data/.yardopts +1 -0
  7. data/CHANGELOG.md +113 -0
  8. data/Gemfile +28 -0
  9. data/Gemfile.lock +245 -0
  10. data/Guardfile +35 -0
  11. data/LICENSE +277 -0
  12. data/README.md +23 -0
  13. data/Rakefile +406 -0
  14. data/bin/console +15 -0
  15. data/bin/setup +8 -0
  16. data/config/userdata/config/org/openhab/restauth.config +3 -0
  17. data/cucumber.yml +1 -0
  18. data/docs/_config.yml +135 -0
  19. data/docs/contributing/index.md +47 -0
  20. data/docs/examples/conversions.md +123 -0
  21. data/docs/examples/index.md +61 -0
  22. data/docs/index.md +19 -0
  23. data/docs/installation/index.md +26 -0
  24. data/docs/motivation/index.md +27 -0
  25. data/docs/usage/execution.md +9 -0
  26. data/docs/usage/execution/delay.md +48 -0
  27. data/docs/usage/execution/otherwise.md +30 -0
  28. data/docs/usage/execution/run.md +70 -0
  29. data/docs/usage/execution/triggered.md +48 -0
  30. data/docs/usage/guards.md +51 -0
  31. data/docs/usage/guards/between.md +30 -0
  32. data/docs/usage/guards/not_if.md +41 -0
  33. data/docs/usage/guards/only_if.md +40 -0
  34. data/docs/usage/index.md +11 -0
  35. data/docs/usage/items.md +66 -0
  36. data/docs/usage/items/contact.md +84 -0
  37. data/docs/usage/items/dimmer.md +147 -0
  38. data/docs/usage/items/groups.md +76 -0
  39. data/docs/usage/items/number.md +225 -0
  40. data/docs/usage/items/string.md +49 -0
  41. data/docs/usage/items/switch.md +85 -0
  42. data/docs/usage/misc.md +7 -0
  43. data/docs/usage/misc/actions.md +108 -0
  44. data/docs/usage/misc/duration.md +21 -0
  45. data/docs/usage/misc/gems.md +25 -0
  46. data/docs/usage/misc/logging.md +21 -0
  47. data/docs/usage/misc/metadata.md +128 -0
  48. data/docs/usage/misc/store_states.md +42 -0
  49. data/docs/usage/misc/time_of_day.md +69 -0
  50. data/docs/usage/misc/timers.md +67 -0
  51. data/docs/usage/rule.md +43 -0
  52. data/docs/usage/things.md +29 -0
  53. data/docs/usage/triggers.md +8 -0
  54. data/docs/usage/triggers/changed.md +57 -0
  55. data/docs/usage/triggers/channel.md +54 -0
  56. data/docs/usage/triggers/command.md +69 -0
  57. data/docs/usage/triggers/cron.md +19 -0
  58. data/docs/usage/triggers/every.md +76 -0
  59. data/docs/usage/triggers/updated.md +78 -0
  60. data/lib/openhab.rb +39 -0
  61. data/lib/openhab/configuration.rb +16 -0
  62. data/lib/openhab/core/cron.rb +27 -0
  63. data/lib/openhab/core/debug.rb +34 -0
  64. data/lib/openhab/core/dsl.rb +47 -0
  65. data/lib/openhab/core/dsl/actions.rb +107 -0
  66. data/lib/openhab/core/dsl/entities.rb +103 -0
  67. data/lib/openhab/core/dsl/gems.rb +29 -0
  68. data/lib/openhab/core/dsl/group.rb +91 -0
  69. data/lib/openhab/core/dsl/items/items.rb +39 -0
  70. data/lib/openhab/core/dsl/items/number_item.rb +217 -0
  71. data/lib/openhab/core/dsl/items/string_item.rb +102 -0
  72. data/lib/openhab/core/dsl/monkey_patch/actions/actions.rb +4 -0
  73. data/lib/openhab/core/dsl/monkey_patch/actions/script_thing_actions.rb +22 -0
  74. data/lib/openhab/core/dsl/monkey_patch/events.rb +5 -0
  75. data/lib/openhab/core/dsl/monkey_patch/events/item_command.rb +13 -0
  76. data/lib/openhab/core/dsl/monkey_patch/events/item_state_changed.rb +25 -0
  77. data/lib/openhab/core/dsl/monkey_patch/events/thing_status_info.rb +26 -0
  78. data/lib/openhab/core/dsl/monkey_patch/items/contact_item.rb +54 -0
  79. data/lib/openhab/core/dsl/monkey_patch/items/dimmer_item.rb +125 -0
  80. data/lib/openhab/core/dsl/monkey_patch/items/group_item.rb +27 -0
  81. data/lib/openhab/core/dsl/monkey_patch/items/items.rb +130 -0
  82. data/lib/openhab/core/dsl/monkey_patch/items/metadata.rb +259 -0
  83. data/lib/openhab/core/dsl/monkey_patch/items/switch_item.rb +86 -0
  84. data/lib/openhab/core/dsl/monkey_patch/ruby/number.rb +69 -0
  85. data/lib/openhab/core/dsl/monkey_patch/ruby/range.rb +46 -0
  86. data/lib/openhab/core/dsl/monkey_patch/ruby/ruby.rb +5 -0
  87. data/lib/openhab/core/dsl/monkey_patch/types/decimal_type.rb +24 -0
  88. data/lib/openhab/core/dsl/monkey_patch/types/on_off_type.rb +41 -0
  89. data/lib/openhab/core/dsl/monkey_patch/types/open_closed_type.rb +25 -0
  90. data/lib/openhab/core/dsl/monkey_patch/types/percent_type.rb +23 -0
  91. data/lib/openhab/core/dsl/monkey_patch/types/types.rb +7 -0
  92. data/lib/openhab/core/dsl/property.rb +85 -0
  93. data/lib/openhab/core/dsl/rule/channel.rb +41 -0
  94. data/lib/openhab/core/dsl/rule/cron.rb +115 -0
  95. data/lib/openhab/core/dsl/rule/guard.rb +99 -0
  96. data/lib/openhab/core/dsl/rule/item.rb +207 -0
  97. data/lib/openhab/core/dsl/rule/rule.rb +374 -0
  98. data/lib/openhab/core/dsl/rule/triggers.rb +77 -0
  99. data/lib/openhab/core/dsl/states.rb +63 -0
  100. data/lib/openhab/core/dsl/things.rb +93 -0
  101. data/lib/openhab/core/dsl/time_of_day.rb +203 -0
  102. data/lib/openhab/core/dsl/timers.rb +85 -0
  103. data/lib/openhab/core/dsl/types/quantity.rb +255 -0
  104. data/lib/openhab/core/dsl/units.rb +41 -0
  105. data/lib/openhab/core/duration.rb +69 -0
  106. data/lib/openhab/core/log.rb +175 -0
  107. data/lib/openhab/core/patch_load_path.rb +7 -0
  108. data/lib/openhab/core/startup_delay.rb +22 -0
  109. data/lib/openhab/osgi.rb +52 -0
  110. data/lib/openhab/version.rb +9 -0
  111. data/openhab-scripting.gemspec +30 -0
  112. data/openhab_rules/warmup.rb +5 -0
  113. metadata +157 -0
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'securerandom'
4
+
5
+ module OpenHAB
6
+ module Core
7
+ module DSL
8
+ module Rule
9
+ #
10
+ # Class for creating and managing triggers
11
+ #
12
+ class Trigger
13
+ java_import org.openhab.core.automation.util.TriggerBuilder
14
+ java_import org.openhab.core.config.core.Configuration
15
+
16
+ # @return [String] A channel event trigger
17
+ CHANNEL_EVENT = 'core.ChannelEventTrigger'
18
+
19
+ # @return [String] A thing status Change trigger
20
+ THING_CHANGE = 'core.ThingStatusChangeTrigger'
21
+
22
+ # @return [String] A thing status update trigger
23
+ THING_UPDATE = 'core.ThingStatusUpdateTrigger'
24
+
25
+ # @return [String] An item command trigger
26
+ ITEM_COMMAND = 'core.ItemCommandTrigger'
27
+
28
+ # @return [String] An item state update trigger
29
+ ITEM_STATE_UPDATE = 'core.ItemStateUpdateTrigger'
30
+
31
+ # @return [String] An item state change trigger
32
+ ITEM_STATE_CHANGE = 'core.ItemStateChangeTrigger'
33
+
34
+ # @return [String] A group state change trigger for items in the group
35
+ GROUP_STATE_CHANGE = 'core.GroupStateChangeTrigger'
36
+
37
+ # @return [String] A group state update trigger for items in the group
38
+ GROUP_STATE_UPDATE = 'core.GroupStateUpdateTrigger'
39
+
40
+ # @return [String] A group command trigger for items in the group
41
+ GROUP_COMMAND = 'core.GroupCommandTrigger'
42
+
43
+ # @return [String] A time of day trigger
44
+ TIME_OF_DAY = 'timer.TimeOfDayTrigger'
45
+
46
+ # @return [String] A cron trigger
47
+ CRON = 'timer.GenericCronTrigger'
48
+
49
+ #
50
+ # Create a trigger
51
+ #
52
+ # @param [String] type of trigger
53
+ # @param [Map] config map
54
+ #
55
+ # @return [OpenHAB Trigger] configured by type and supplied config
56
+ #
57
+ def self.trigger(type:, config:)
58
+ TriggerBuilder.create
59
+ .with_id(uuid)
60
+ .with_type_uid(type)
61
+ .with_configuration(Configuration.new(config))
62
+ .build
63
+ end
64
+
65
+ #
66
+ # Generate a UUID for triggers
67
+ #
68
+ # @return [String] UUID
69
+ #
70
+ def self.uuid
71
+ SecureRandom.uuid
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'delegate'
4
+
5
+ module OpenHAB
6
+ module Core
7
+ module DSL
8
+ #
9
+ # Manages storing and restoring item state
10
+ #
11
+ module States
12
+ java_import org.openhab.core.model.script.actions.BusEvent
13
+
14
+ #
15
+ # Delegates state storage to a Hash providing methods to operate with states
16
+ #
17
+ class StateStorage < SimpleDelegator
18
+ #
19
+ # Restore the stored states of all items
20
+ #
21
+ #
22
+ def restore
23
+ BusEvent.restoreStates(to_h)
24
+ end
25
+
26
+ #
27
+ # Restore states for items that have changed
28
+ #
29
+ #
30
+ def restore_changes
31
+ BusEvent.restoreStates(select { |item, value| item != value })
32
+ end
33
+
34
+ #
35
+ # Detect if any item have changed states since being stored
36
+ #
37
+ # @return [Boolean] True if any items have changed states, false otherwise
38
+ #
39
+ def changed?
40
+ any? { |item, value| item != value }
41
+ end
42
+ end
43
+
44
+ #
45
+ # Store states of supplied items
46
+ #
47
+ # @param [Array] items to store states of
48
+ #
49
+ # @return [StateStorage] item states
50
+ #
51
+ def store_states(*items)
52
+ items = items.flatten.map { |item| item.is_a?(Group) ? item.group : item }
53
+ states = StateStorage.new(BusEvent.storeStates(*items).to_h)
54
+ if block_given?
55
+ yield
56
+ states.restore
57
+ end
58
+ states
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,93 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'java'
4
+ require 'core/log'
5
+ require 'core/dsl/actions'
6
+ require 'delegate'
7
+
8
+ module OpenHAB
9
+ module Core
10
+ module DSL
11
+ #
12
+ # Support for OpenHAB Things
13
+ #
14
+ module Things
15
+ include Logging
16
+
17
+ #
18
+ # Ruby Delegator for Thing
19
+ #
20
+ class Thing < SimpleDelegator
21
+ include OpenHAB::Core::DSL::Actions
22
+ include Logging
23
+
24
+ def initialize(thing)
25
+ super
26
+ define_action_methods
27
+ end
28
+
29
+ private
30
+
31
+ java_import 'org.openhab.core.automation.annotation.RuleAction'
32
+
33
+ #
34
+ # Define methods from actions mapped to this thing
35
+ #
36
+ #
37
+ def define_action_methods
38
+ actions_for_thing(uid).each do |action|
39
+ methods = action.java_class.declared_instance_methods
40
+ methods.select { |method| method.annotation_present?(RuleAction.java_class) }
41
+ .each { |method| define_action_method(action: action, method: method.name) }
42
+ end
43
+ end
44
+
45
+ #
46
+ # Define a method, delegating to supplied action class
47
+ #
48
+ # @param [Object] action object to delegate method to
49
+ # @param [String] method Name of method to delegate
50
+ #
51
+ #
52
+ def define_action_method(action:, method:)
53
+ logger.trace("Adding action method '#{method}' to thing '#{uid}'")
54
+ define_singleton_method(method) do |*args|
55
+ action.public_send(method, *args)
56
+ end
57
+ end
58
+ end
59
+
60
+ #
61
+ # Wraps all Things in a delegator to underlying set and provides lookup method
62
+ #
63
+ class Things < SimpleDelegator
64
+ java_import org.openhab.core.thing.ThingUID
65
+
66
+ # Gets a specific thing by name in the format binding_id:type_id:thing_id
67
+ # @return Thing specified by name or nil if name does not exist in thing registry
68
+ def[](uid)
69
+ thing_uid = ThingUID.new(*uid.split(':'))
70
+ # rubocop: disable Style/GlobalVars
71
+ thing = $things.get(thing_uid)
72
+ # rubocop: enable Style/GlobalVars
73
+ return unless thing
74
+
75
+ logger.trace("Retrieved Thing(#{thing}) from registry for uid: #{uid}")
76
+ Thing.new(thing)
77
+ end
78
+ end
79
+
80
+ #
81
+ # Get all things known to OpenHAB
82
+ #
83
+ # @return [Set] of all Thing objects known to openhab
84
+ #
85
+ def things
86
+ # rubocop: disable Style/GlobalVars
87
+ Things.new($things.getAll.map { |thing| Thing.new(thing) }.to_set)
88
+ # rubocop: enable Style/GlobalVars
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,203 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'java'
4
+ require 'core/log'
5
+ require 'time'
6
+ require 'date'
7
+
8
+ module OpenHAB
9
+ module Core
10
+ module DSL
11
+ # Namespace for classes and modules that handle Time Of Day - Times without specific dates e.g. 6:00:00
12
+ # @author Brian O'Connell
13
+ # @since 0.0.1
14
+ module Tod
15
+ java_import java.time.LocalTime
16
+ java_import java.time.format.DateTimeFormatterBuilder
17
+ java_import java.util.Locale
18
+
19
+ # Class that encapsulates a Time of Day, often viewed as hour-minute-second
20
+ # @author Brian O'Connell
21
+ # @since 0.0.1
22
+ class TimeOfDay
23
+ include Comparable
24
+
25
+ # Immutable Java object containing Time Of Day
26
+ # @return [Java.Time.LocalTime] reprsenting the Time Of Day
27
+ attr_reader :local_time
28
+
29
+ # Constructs a TimeOfDay representing the time when called
30
+ # @since 0.0.1
31
+ # @return [TimeOfDay] representing time when method was invoked
32
+ def self.now
33
+ now = LocalTime.now()
34
+ TimeOfDay.new(h: now.hour, m: now.minute, s: now.second)
35
+ end
36
+
37
+ # Constructs a TimeOfDay representing midnight
38
+ # @since 0.0.1
39
+ # @return [TimeOfDay] representing midnight
40
+ def self.midnight
41
+ TimeOfDay.new(h: 0, m: 0, s: 0)
42
+ end
43
+
44
+ # Constructs a TimeOfDay representing noon
45
+ # @since 0.0.1
46
+ # @return [TimeOfDay] representing noon
47
+ def self.noon
48
+ TimeOfDay.new(h: 12, m: 0, s: 0)
49
+ end
50
+
51
+ # Constructs a TimeOfDay representing the time when called
52
+ # @since 0.0.1
53
+ # @param [String] string representation of TimeOfDay. Valid formats include "HH:MM:SS", "HH:MM", "H:MM", "HH", "H", "H:MM am"
54
+ # @return [TimeOfDay] object created by parsing supplied string
55
+ def self.parse(string)
56
+ format = /(am|pm)$/i.match?(string) ? 'h[:mm[:ss]][ ]a' : 'H[:mm[:ss]]'
57
+ local_time = LocalTime.parse(string, DateTimeFormatterBuilder.new
58
+ .parseCaseInsensitive.appendPattern(format).toFormatter(Locale::ENGLISH))
59
+ TimeOfDay.new(h: local_time.hour, m: local_time.minute, s: local_time.second)
60
+ rescue java.time.format.DateTimeParseException => e
61
+ raise ArgumentError, e.message
62
+ end
63
+
64
+ # Constructs a TimeOfDay representing the time when called
65
+ # @since 0.0.1
66
+ # @option opts [Number] :h Hour of the day, defaults to 0
67
+ # @option opts [Number] :m Minute of the day, defaults to 0
68
+ # @option opts [Number] :s Second of the day, defaults to 0
69
+ # @return [TimeOfDay] representing time when method was invoked
70
+ def initialize(h: 0, m: 0, s: 0)
71
+ @local_time = LocalTime.of(h, m, s)
72
+ freeze
73
+ end
74
+
75
+ # Returns true if the time falls within a range
76
+ def between?(range)
77
+ between(range).cover? self
78
+ end
79
+
80
+ # Returns the hour of the TimeOfDay
81
+ # @since 0.0.1
82
+ # @return [Number] Hour of the day, from 0 to 23
83
+ def hour
84
+ @local_time.hour
85
+ end
86
+
87
+ # Returns the minute of the TimeOfDay
88
+ # @since 0.0.1
89
+ # @return [Number] minute of the day, from 0 to 59
90
+ def minute
91
+ @local_time.minute
92
+ end
93
+
94
+ # Returns the second of the TimeOfDay
95
+ # @since 0.0.1
96
+ # @return [Number] second of the day, from 0 to 59
97
+ def second
98
+ @local_time.second
99
+ end
100
+
101
+ # Returns the string representation of the TimeOfDay
102
+ # @since 0.0.1
103
+ # @return [String] in any of the following formats depending on time representation HH:mm, HH:mm:ss, HH:mm:ss.SSS, HH:mm:ss.SSSSSS, HH:mm:ss.SSSSSSSSS
104
+ def to_s
105
+ @local_time.to_s
106
+ end
107
+
108
+ # Compares one TimeOfDay to another
109
+ # @since 0.0.1
110
+ # @return [Number, nil] -1,0,1 if other TimeOfDay is less than, equal to, or greater than this TimeOfDay or nil if an object other than TimeOfDay is provided
111
+ def <=>(other)
112
+ case other
113
+ when TimeOfDay
114
+ @local_time.compare_to(other.local_time)
115
+ when String
116
+ @local_time.compare_to(TimeOfDay.parse(other).local_time)
117
+ else
118
+ -(other <=> self)
119
+ end
120
+ end
121
+ end
122
+
123
+ # Modules that refines the Ruby Range object cover? and include? methods to support TimeOfDay ranges
124
+ class TimeOfDayRangeElement
125
+ include Comparable
126
+ include Logging
127
+
128
+ NUM_SECONDS_IN_DAY = (60 * 60 * 24)
129
+
130
+ attr_reader :sod
131
+
132
+ def initialize(sod:, range_begin:)
133
+ @sod = sod
134
+ @range_begin = range_begin
135
+ end
136
+
137
+ # Returns the current second of day advanced by 1 second
138
+ def succ
139
+ TimeOfDayRangeElement.new(sod: @sod + 1, range_begin: @range_begin)
140
+ end
141
+
142
+ # Compares one TimeOfDayRangeElement to another
143
+ # @since 2.4.0
144
+ # @return [Number, nil] -1,0,1 if other is less than, equal to, or greater than this TimeOfDay
145
+ def <=>(other)
146
+ other_second_of_day = case other
147
+ when TimeOfDay
148
+ adjust_second_of_day(other.local_time.to_second_of_day)
149
+ when String
150
+ adjust_second_of_day(TimeOfDay.parse(other).local_time.to_second_of_day)
151
+ when Time
152
+ adjust_second_of_day(TimeOfDay.new(h: other.hour, m: other.min,
153
+ s: other.sec).local_time.to_second_of_day)
154
+ when TimeOfDayRangeElement
155
+ other.sod
156
+ else
157
+ raise ArgumentError, 'Supplied argument cannot be converted into Time Of Day Object'
158
+ end
159
+
160
+ logger.trace do
161
+ "SOD(#{sod}) other SOD(#{other_second_of_day}) Other Class (#{other.class}) Result (#{sod <=> other_second_of_day})"
162
+ end
163
+ sod <=> other_second_of_day
164
+ end
165
+
166
+ private
167
+
168
+ def adjust_second_of_day(second_of_day)
169
+ second_of_day += NUM_SECONDS_IN_DAY if second_of_day < @range_begin
170
+ second_of_day
171
+ end
172
+ end
173
+
174
+ # Creates a range that can be compared against time of day objects or strings
175
+ # to see if they are within the range
176
+ # @since 2.4.0
177
+ # @return Range object representing a TimeOfDay Range
178
+ def between(range)
179
+ raise ArgumentError, 'Supplied object must be a range' unless range.is_a? Range
180
+
181
+ start = range.begin
182
+ ending = range.end
183
+
184
+ start = TimeOfDay.parse(start) if start.is_a? String
185
+ ending = TimeOfDay.parse(ending) if ending.is_a? String
186
+
187
+ start_sod = start.local_time.to_second_of_day
188
+ ending_sod = ending.local_time.to_second_of_day
189
+ ending_sod += TimeOfDayRangeElement::NUM_SECONDS_IN_DAY if ending_sod < start_sod
190
+
191
+ start_range = TimeOfDayRangeElement.new(sod: start_sod, range_begin: start_sod)
192
+ ending_range = TimeOfDayRangeElement.new(sod: ending_sod, range_begin: start_sod)
193
+ range.exclude_end? ? (start_range...ending_range) : (start_range..ending_range)
194
+ end
195
+ module_function :between
196
+
197
+ MIDNIGHT = TimeOfDay.midnight
198
+ NOON = TimeOfDay.noon
199
+ ALL_DAY = between(TimeOfDay.new(h: 0, m: 0, s: 0)..TimeOfDay.new(h: 23, m: 59, s: 59))
200
+ end
201
+ end
202
+ end
203
+ end
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'java'
4
+ require 'delegate'
5
+ require 'forwardable'
6
+
7
+ require 'core/duration'
8
+
9
+ module OpenHAB
10
+ module Core
11
+ module DSL
12
+ #
13
+ # Provides access to and ruby wrappers around OpenHAB timers
14
+ #
15
+ module Timers
16
+ java_import org.openhab.core.model.script.actions.ScriptExecution
17
+ java_import java.time.ZonedDateTime
18
+
19
+ # Ruby wrapper for OpenHAB Timer
20
+ # This class implements delegator to delegate methods to the OpenHAB timer
21
+ #
22
+ # @author Brian O'Connell
23
+ # @since 2.0.0
24
+ class Timer < SimpleDelegator
25
+ extend Forwardable
26
+
27
+ def_delegator :@timer, :is_active, :active?
28
+ def_delegator :@timer, :is_running, :running?
29
+ def_delegator :@timer, :has_terminated, :terminated?
30
+
31
+ #
32
+ # Create a new Timer Object
33
+ #
34
+ # @param [Duration] duration Duration until timer should fire
35
+ # @param [Block] block Block to execute when timer fires
36
+ #
37
+ def initialize(duration:, &block)
38
+ @duration = duration
39
+
40
+ # A semaphore is used to prevent a race condition in which calling the block from the timer thread
41
+ # occurs before the @timer variable can be set resulting in @timer being nil
42
+ semaphore = Mutex.new
43
+
44
+ @block = proc do
45
+ semaphore.synchronize do
46
+ block.call(self)
47
+ end
48
+ end
49
+
50
+ semaphore.synchronize do
51
+ @timer = ScriptExecution.createTimer(
52
+ ZonedDateTime.now.plus(Java::JavaTime::Duration.ofMillis(@duration.to_ms)), @block
53
+ )
54
+ super(@timer)
55
+ end
56
+ end
57
+
58
+ #
59
+ # Reschedule timer
60
+ #
61
+ # @param [Duration] duration
62
+ #
63
+ # @return [<Type>] <description>
64
+ #
65
+ def reschedule(duration = nil)
66
+ duration ||= @duration
67
+ @timer.reschedule(ZonedDateTime.now.plus(Java::JavaTime::Duration.ofMillis(duration.to_ms)))
68
+ end
69
+ end
70
+
71
+ #
72
+ # Execute the supplied block after the specified duration
73
+ #
74
+ # @param [Duration] duration after which to execute the block
75
+ # @param [Block] block to execute, block is passed a Timer object
76
+ #
77
+ # @return [Timer] Timer object
78
+ #
79
+ def after(duration, &block)
80
+ Timer.new(duration: duration, &block)
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end