openhab-scripting 2.9.1

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 (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