openhab-scripting 5.10.0 → 5.12.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/openhab/core/events/channel_triggered_event.rb +30 -0
- data/lib/openhab/core/events/item_state_updated_event.rb +4 -3
- data/lib/openhab/core/items/dimmer_item.rb +2 -2
- data/lib/openhab/core/items/generic_item.rb +7 -1
- data/lib/openhab/core/items/player_item.rb +17 -0
- data/lib/openhab/core/items/rollershutter_item.rb +8 -0
- data/lib/openhab/core/items/semantics/enumerable.rb +19 -0
- data/lib/openhab/core/items/switch_item.rb +10 -2
- data/lib/openhab/core/items.rb +36 -12
- data/lib/openhab/core/profile_factory.rb +48 -7
- data/lib/openhab/core/sitemaps/provider.rb +6 -2
- data/lib/openhab/core/things/channel_uid.rb +10 -0
- data/lib/openhab/core/things/profile_callback.rb +4 -3
- data/lib/openhab/core/things/thing.rb +1 -0
- data/lib/openhab/core/types/decimal_type.rb +1 -1
- data/lib/openhab/core/types/quantity_type.rb +2 -2
- data/lib/openhab/dsl/config_description/builder.rb +157 -0
- data/lib/openhab/dsl/items/ensure.rb +5 -1
- data/lib/openhab/dsl/sitemaps/builder.rb +85 -48
- data/lib/openhab/dsl/things/builder.rb +27 -12
- data/lib/openhab/dsl/version.rb +1 -1
- data/lib/openhab/dsl.rb +91 -10
- data/lib/openhab/rspec/shell.rb +27 -17
- data/lib/openhab/yard/code_objects/java/base.rb +3 -1
- data/lib/openhab/yard/code_objects/java/method_object.rb +15 -0
- data/lib/openhab/yard/handlers/jruby/base.rb +71 -16
- metadata +5 -16
@@ -36,12 +36,9 @@ module OpenHAB
|
|
36
36
|
# Base class for all widgets
|
37
37
|
# @see org.openhab.core.model.sitemap.sitemap.Widget
|
38
38
|
class WidgetBuilder
|
39
|
-
#
|
40
|
-
|
41
|
-
|
42
|
-
COLOR_PATTERN = /((?<item>[A-Za-z]\w*)?\s*((?<condition>==|!=|<=|>=|<|>)\s*(?<sign>\+|-)?(?<state>\S+))?\s*=)?\s*(?<arg>\S+)/.freeze
|
43
|
-
# rubocop:enable Layout/LineLength, Lint/MixedRegexpCaptureTypes
|
44
|
-
private_constant :VISIBILITY_PATTERN, :COLOR_PATTERN
|
39
|
+
# This is copied directly out of UIComponentSitemapProvider.java
|
40
|
+
CONDITION_PATTERN = /(?<item>[A-Za-z]\w*)?\s*(?<condition>==|!=|<=|>=|<|>)?\s*(?<sign>\+|-)?(?<state>.+)/.freeze
|
41
|
+
private_constant :CONDITION_PATTERN
|
45
42
|
|
46
43
|
# @return [String, nil]
|
47
44
|
attr_accessor :label
|
@@ -52,15 +49,15 @@ module OpenHAB
|
|
52
49
|
# @see https://www.openhab.org/docs/ui/sitemaps.html#icons
|
53
50
|
attr_accessor :icon
|
54
51
|
# Label color rules
|
55
|
-
# @return [
|
52
|
+
# @return [Hash<String, String>]
|
56
53
|
# @see https://www.openhab.org/docs/ui/sitemaps.html#label-value-and-icon-colors
|
57
54
|
attr_reader :label_colors
|
58
55
|
# Value color rules
|
59
|
-
# @return [
|
56
|
+
# @return [Hash<String, String>]
|
60
57
|
# @see https://www.openhab.org/docs/ui/sitemaps.html#label-value-and-icon-colors
|
61
58
|
attr_reader :value_colors
|
62
59
|
# Icon color rules
|
63
|
-
# @return [
|
60
|
+
# @return [Hash<String, String>]
|
64
61
|
# @see https://www.openhab.org/docs/ui/sitemaps.html#label-value-and-icon-colors
|
65
62
|
attr_reader :icon_colors
|
66
63
|
# Visibility rules
|
@@ -94,32 +91,32 @@ module OpenHAB
|
|
94
91
|
@label = label
|
95
92
|
@icon = icon
|
96
93
|
@visibilities = []
|
97
|
-
@label_colors =
|
98
|
-
@value_colors =
|
99
|
-
@icon_colors =
|
94
|
+
@label_colors = {}
|
95
|
+
@value_colors = {}
|
96
|
+
@icon_colors = {}
|
100
97
|
|
101
|
-
self.label_color(
|
102
|
-
self.value_color(
|
103
|
-
self.icon_color(
|
98
|
+
self.label_color(label_color) if label_color
|
99
|
+
self.value_color(value_color) if value_color
|
100
|
+
self.icon_color(icon_color) if icon_color
|
104
101
|
self.visibility(*visibility) if visibility
|
105
102
|
end
|
106
103
|
|
107
104
|
# Adds one or more new rules for setting the label color
|
108
|
-
# @return [
|
109
|
-
def label_color(
|
110
|
-
@label_colors.
|
105
|
+
# @return [Hash<String, String>] the current rules
|
106
|
+
def label_color(rules)
|
107
|
+
@label_colors.merge!(rules)
|
111
108
|
end
|
112
109
|
|
113
110
|
# Adds one or more new rules for setting the value color
|
114
|
-
# @return [
|
115
|
-
def value_color(
|
116
|
-
@value_colors.
|
111
|
+
# @return [Hash<String, String>] the current rules
|
112
|
+
def value_color(rules)
|
113
|
+
@value_colors.merge!(rules)
|
117
114
|
end
|
118
115
|
|
119
116
|
# Adds one or more new rules for setting the icon color
|
120
|
-
# @return [
|
121
|
-
def icon_color(
|
122
|
-
@icon_colors.
|
117
|
+
# @return [Hash<String, String>] the current rules
|
118
|
+
def icon_color(rules)
|
119
|
+
@icon_colors.merge!(rules)
|
123
120
|
end
|
124
121
|
|
125
122
|
# Adds one or more new visibility rules
|
@@ -137,21 +134,28 @@ module OpenHAB
|
|
137
134
|
widget.label = @label
|
138
135
|
widget.icon = @icon
|
139
136
|
|
140
|
-
|
141
|
-
|
142
|
-
|
137
|
+
add_colors(widget, :label_color, label_colors)
|
138
|
+
add_colors(widget, :value_color, value_colors)
|
139
|
+
add_colors(widget, :icon_color, icon_colors)
|
143
140
|
|
144
|
-
|
145
|
-
|
146
|
-
|
141
|
+
# @deprecated OH 4.1
|
142
|
+
if SitemapBuilder.factory.respond_to?(:create_condition)
|
143
|
+
add_conditions(widget, :visibility, visibilities, :create_visibility_rule)
|
144
|
+
else
|
145
|
+
visibilities.each do |v|
|
146
|
+
raise ArgumentError, "AND conditions not supported prior to openHAB 4.1" if v.is_a?(Array)
|
147
|
+
|
148
|
+
unless (match = CONDITION_PATTERN.match(v))
|
149
|
+
raise ArgumentError, "Syntax error in visibility rule #{v.inspect}"
|
150
|
+
end
|
151
|
+
|
152
|
+
rule = SitemapBuilder.factory.create_visibility_rule
|
153
|
+
rule.item = match["item"]
|
154
|
+
rule.condition = match["condition"]
|
155
|
+
rule.sign = match["sign"]
|
156
|
+
rule.state = match["state"]
|
157
|
+
widget.visibility.add(rule)
|
147
158
|
end
|
148
|
-
|
149
|
-
rule = SitemapBuilder.factory.create_visibility_rule
|
150
|
-
rule.item = match["item"]
|
151
|
-
rule.condition = match["condition"]
|
152
|
-
rule.sign = match["sign"]
|
153
|
-
rule.state = match["state"]
|
154
|
-
widget.visibility.add(rule)
|
155
159
|
end
|
156
160
|
|
157
161
|
widget
|
@@ -169,19 +173,51 @@ module OpenHAB
|
|
169
173
|
|
170
174
|
private
|
171
175
|
|
172
|
-
def
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
+
def add_colors(widget, method, conditions)
|
177
|
+
conditions.each do |condition, color|
|
178
|
+
condition = [condition] unless condition.is_a?(Array)
|
179
|
+
add_conditions(widget, method, condition, :create_color_array) do |color_array|
|
180
|
+
color_array.arg = color
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
def add_conditions(widget, method, conditions, container_method)
|
186
|
+
return if conditions.empty?
|
187
|
+
|
188
|
+
object = widget.send(method)
|
189
|
+
has_and_conditions = conditions.any?(Array)
|
190
|
+
# @deprecated OH 4.1
|
191
|
+
if !SitemapBuilder.factory.respond_to?(:create_condition) && has_and_conditions
|
192
|
+
raise ArgumentError, "AND conditions not supported prior to openHAB 4.1"
|
193
|
+
end
|
194
|
+
|
195
|
+
conditions = [conditions] unless has_and_conditions
|
196
|
+
|
197
|
+
conditions.each do |sub_conditions|
|
198
|
+
container = SitemapBuilder.factory.send(container_method)
|
199
|
+
|
200
|
+
add_conditions_to_container(container, sub_conditions)
|
201
|
+
yield container if block_given?
|
202
|
+
object.add(container)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
def add_conditions_to_container(container, conditions)
|
207
|
+
# @deprecated OH 4.1
|
208
|
+
supports_and_conditions = SitemapBuilder.factory.respond_to?(:create_condition)
|
209
|
+
|
210
|
+
Array.wrap(conditions).each do |c|
|
211
|
+
unless (match = CONDITION_PATTERN.match(c))
|
212
|
+
raise ArgumentError, "Syntax error in condition #{c.inspect}"
|
176
213
|
end
|
177
214
|
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
widget_color.add(color)
|
215
|
+
condition = supports_and_conditions ? SitemapBuilder.factory.create_condition : container
|
216
|
+
condition.item = match["item"]
|
217
|
+
condition.condition = match["condition"]
|
218
|
+
condition.sign = match["sign"]
|
219
|
+
condition.state = match["state"]
|
220
|
+
container.conditions.add(condition) if supports_and_conditions
|
185
221
|
end
|
186
222
|
end
|
187
223
|
end
|
@@ -284,6 +320,7 @@ module OpenHAB
|
|
284
320
|
|
285
321
|
@switch = switch
|
286
322
|
@frequency = frequency
|
323
|
+
@switch_enabled = nil
|
287
324
|
end
|
288
325
|
|
289
326
|
# (see #switch=)
|
@@ -210,7 +210,18 @@ module OpenHAB
|
|
210
210
|
thing_type,
|
211
211
|
self.class.config_description_registry
|
212
212
|
)
|
213
|
+
|
214
|
+
predefined_channels = self.class.thing_factory_helper
|
215
|
+
.create_channels(thing_type, uid, self.class.config_description_registry)
|
216
|
+
.to_h { |channel| [channel.uid, channel] }
|
217
|
+
new_channels = channels.to_h { |channel| [channel.uid, channel] }
|
218
|
+
merged_channels = predefined_channels.merge(new_channels) do |_key, predefined_channel, new_channel|
|
219
|
+
predefined_channel.configuration.merge!(new_channel.configuration)
|
220
|
+
predefined_channel
|
221
|
+
end
|
222
|
+
@channels = merged_channels.values
|
213
223
|
end
|
224
|
+
|
214
225
|
builder = org.openhab.core.thing.binding.builder.ThingBuilder
|
215
226
|
.create(thing_type_uid, uid)
|
216
227
|
.with_label(label)
|
@@ -219,15 +230,7 @@ module OpenHAB
|
|
219
230
|
.with_bridge(bridge_uid)
|
220
231
|
.with_channels(channels)
|
221
232
|
|
222
|
-
if thing_type
|
223
|
-
# can't use with_channels, or it will wipe out custom channels from above
|
224
|
-
self.class.thing_factory_helper.create_channels(thing_type,
|
225
|
-
uid,
|
226
|
-
self.class.config_description_registry).each do |channel|
|
227
|
-
builder.with_channel(channel)
|
228
|
-
end
|
229
|
-
builder.with_properties(thing_type.properties)
|
230
|
-
end
|
233
|
+
builder.with_properties(thing_type.properties) if thing_type
|
231
234
|
|
232
235
|
builder.build
|
233
236
|
end
|
@@ -263,8 +266,14 @@ module OpenHAB
|
|
263
266
|
:default_tags,
|
264
267
|
:properties,
|
265
268
|
:description,
|
266
|
-
:auto_update_policy
|
267
|
-
|
269
|
+
:auto_update_policy
|
270
|
+
|
271
|
+
class << self
|
272
|
+
# @!visibility private
|
273
|
+
def channel_type_registry
|
274
|
+
@channel_type_registry ||= OSGi.service("org.openhab.core.thing.type.ChannelTypeRegistry")
|
275
|
+
end
|
276
|
+
end
|
268
277
|
|
269
278
|
#
|
270
279
|
# Constructor for ChannelBuilder
|
@@ -284,7 +293,7 @@ module OpenHAB
|
|
284
293
|
# The default tags for this channel.
|
285
294
|
# @param [:default, :recommend, :veto, org.openhab.core.thing.type.AutoUpdatePolicy] auto_update_policy
|
286
295
|
# The channel's auto update policy.
|
287
|
-
# @param [String] accepted_item_type The accepted item type.
|
296
|
+
# @param [String] accepted_item_type The accepted item type. If nil, infer the item type from the channel type.
|
288
297
|
#
|
289
298
|
def initialize(uid,
|
290
299
|
type,
|
@@ -343,6 +352,12 @@ module OpenHAB
|
|
343
352
|
.build
|
344
353
|
end
|
345
354
|
|
355
|
+
# @!attribute [r] accepted_item_type
|
356
|
+
# @return [String] The accepted item type.
|
357
|
+
def accepted_item_type
|
358
|
+
@accepted_item_type ||= self.class.channel_type_registry.get_channel_type(type)&.item_type
|
359
|
+
end
|
360
|
+
|
346
361
|
private
|
347
362
|
|
348
363
|
def kind
|
data/lib/openhab/dsl/version.rb
CHANGED
data/lib/openhab/dsl.rb
CHANGED
@@ -77,7 +77,13 @@ module OpenHAB
|
|
77
77
|
#
|
78
78
|
# Defines a new profile that can be applied to item channel links.
|
79
79
|
#
|
80
|
+
# To create a profile that can be used in the UI, provide a label and optionally a {config_description},
|
81
|
+
# otherwise the profile will not be visible in the UI.
|
82
|
+
#
|
80
83
|
# @param [String, Symbol] id The id for the profile.
|
84
|
+
# @param [String, nil] label The label for the profile. When nil, the profile will not be visible in the UI.
|
85
|
+
# @param [org.openhab.core.config.core.ConfigDescription, nil] config_description
|
86
|
+
# The configuration description for the profile so that it can be configured in the UI.
|
81
87
|
# @yield [event, command: nil, state: nil, callback:, link:, item:, channel_uid:, configuration:, context:]
|
82
88
|
# All keyword params are optional. Any that aren't defined won't be passed.
|
83
89
|
# @yieldparam [:command_from_item, :state_from_item, :command_from_handler, :state_from_handler] event
|
@@ -97,8 +103,8 @@ module OpenHAB
|
|
97
103
|
# @yieldreturn [Boolean] Return true from the block in order to have default processing.
|
98
104
|
# @return [void]
|
99
105
|
#
|
100
|
-
# @see org.openhab.thing.Profile
|
101
|
-
# @see org.openhab.thing.StateProfile
|
106
|
+
# @see org.openhab.core.thing.profiles.Profile
|
107
|
+
# @see org.openhab.core.thing.profiles.StateProfile
|
102
108
|
#
|
103
109
|
# @example Vetoing a command
|
104
110
|
# profile(:veto_closing_shades) do |event, item:, command:|
|
@@ -142,17 +148,54 @@ module OpenHAB
|
|
142
148
|
# # can also be referenced from an `.items` file:
|
143
149
|
# # Number:Temperature MyTempWithNonUnitValueFromBinding "I prefer Celsius [%d °C]" { channel="something_that_returns_F"[profile="ruby:set_uom", unit="°F"] }
|
144
150
|
#
|
145
|
-
|
151
|
+
# @example Create a profile that is usable in the UI
|
152
|
+
# config_description = config_description do
|
153
|
+
# parameter :min, :decimal, label: "Minimum", description: "Minimum value"
|
154
|
+
# parameter :max, :decimal, label: "Maximum", description: "Maximum value"
|
155
|
+
# end
|
156
|
+
#
|
157
|
+
# profile(:range_filter, label: "Range Filter", config_description: config_description) do |event, state:, configuration:|
|
158
|
+
# return true unless event == :state_from_handler
|
159
|
+
#
|
160
|
+
# (configuration["min"]..configuration["max"]).cover?(state)
|
161
|
+
# end
|
162
|
+
#
|
163
|
+
def profile(id, label: nil, config_description: nil, &block)
|
146
164
|
raise ArgumentError, "Block is required" unless block
|
147
165
|
|
148
166
|
id = id.to_s
|
149
|
-
uid = org.openhab.core.thing.profiles.ProfileTypeUID.new("ruby", id)
|
150
167
|
|
151
168
|
ThreadLocal.thread_local(openhab_rule_type: "profile", openhab_rule_uid: id) do
|
152
|
-
Core::ProfileFactory.instance.register(
|
169
|
+
Core::ProfileFactory.instance.register(id, block, label: label, config_description: config_description)
|
153
170
|
end
|
154
171
|
end
|
155
172
|
|
173
|
+
#
|
174
|
+
# Create a {org.openhab.core.config.core.ConfigDescription ConfigDescription} object.
|
175
|
+
#
|
176
|
+
# @param [String, java.net.URI] uri The URI for the ConfigDescription. When nil, a dummy URI is used which will
|
177
|
+
# be replaced by the profile with the correct URI for that profile.
|
178
|
+
# @yield Block that consists of {ConfigDescription::Builder#parameter} and {ConfigDescription::Builder#group} calls.
|
179
|
+
#
|
180
|
+
# @return [org.openhab.core.config.core.ConfigDescription]
|
181
|
+
# The created {org.openhab.core.config.core.ConfigDescription ConfigDescription} object
|
182
|
+
#
|
183
|
+
# @example
|
184
|
+
# config_description = config_description do
|
185
|
+
# parameter :ungrouped_parameter, :decimal, label: "Ungrouped Parameter", min: 1, max: 5
|
186
|
+
#
|
187
|
+
# group "Config Group", label: "Grouped parameters", advanced: true do
|
188
|
+
# parameter :my_parameter, :string, label: "My Parameter", description: "My Parameter Description"
|
189
|
+
# parameter :other_parameter, :integer, label: "Other Parameter", description: "Other Parameter Description"
|
190
|
+
# end
|
191
|
+
# end
|
192
|
+
#
|
193
|
+
def config_description(uri = nil, &block)
|
194
|
+
raise ArgumentError, "Block is required" unless block
|
195
|
+
|
196
|
+
ConfigDescription::Builder.new.build(uri, &block)
|
197
|
+
end
|
198
|
+
|
156
199
|
# rubocop:enable Layout/LineLength
|
157
200
|
|
158
201
|
# @!group Object Access
|
@@ -557,10 +600,49 @@ module OpenHAB
|
|
557
600
|
# to reduce repetitions
|
558
601
|
#
|
559
602
|
|
603
|
+
#
|
604
|
+
# Permanently enable conditional execution of commands and updates for the current thread.
|
605
|
+
#
|
606
|
+
# When conditional executions are enabled, commands and updates will only be sent if the
|
607
|
+
# item's current state is not the same as the command or updated state.
|
608
|
+
# This eliminates the need to chain the command and update calls through
|
609
|
+
# {DSL::Items::Ensure::Ensurable#ensure ensure}.
|
610
|
+
#
|
611
|
+
# When conditional executions are enabled either by this method or within a block of {ensure_states},
|
612
|
+
# commands and updates can still be forcefully executed using the corresponding bang methods, e.g.
|
613
|
+
# `Item1.on!`, `Item1.command!(50)`, or `Item1.update!(ON)`.
|
614
|
+
#
|
615
|
+
# @note This method is only intended for use at the top level of rule
|
616
|
+
# scripts. If it's used within library methods, or hap-hazardly within
|
617
|
+
# rules, things can get very confusing because the prior state won't be
|
618
|
+
# properly restored.
|
619
|
+
#
|
620
|
+
# @param [Boolean] active Whether to enable or disable conditional executions.
|
621
|
+
# @return [Boolean] The previous ensure_states setting.
|
622
|
+
#
|
623
|
+
# @example Make ensure_states the default for the rest of the script
|
624
|
+
# ensure_states!
|
625
|
+
#
|
626
|
+
# # From now, all commands are "ensured", i.e. only sent when the current state is different
|
627
|
+
# Item1.on
|
628
|
+
# Item2.command(ON)
|
629
|
+
#
|
630
|
+
# # While ensure_states! is active, we can still forcibly send a command
|
631
|
+
# # regardless of the item's current state
|
632
|
+
# Item2.on!
|
633
|
+
#
|
634
|
+
# @see ensure_states
|
635
|
+
#
|
636
|
+
def ensure_states!(active: true)
|
637
|
+
old = Thread.current[:openhab_ensure_states]
|
638
|
+
Thread.current[:openhab_ensure_states] = active
|
639
|
+
old
|
640
|
+
end
|
641
|
+
|
560
642
|
#
|
561
643
|
# Global method that takes a block and for the duration of the block
|
562
644
|
# all commands sent will check if the item is in the command's state
|
563
|
-
# before sending the command.
|
645
|
+
# before sending the command. This also applies to updates.
|
564
646
|
#
|
565
647
|
# @yield
|
566
648
|
# @return [Object] The result of the block.
|
@@ -603,11 +685,10 @@ module OpenHAB
|
|
603
685
|
# end
|
604
686
|
#
|
605
687
|
def ensure_states
|
606
|
-
old =
|
607
|
-
Thread.current[:openhab_ensure_states] = true
|
688
|
+
old = ensure_states!
|
608
689
|
yield
|
609
690
|
ensure
|
610
|
-
|
691
|
+
ensure_states!(active: old)
|
611
692
|
end
|
612
693
|
|
613
694
|
#
|
@@ -841,7 +922,7 @@ module OpenHAB
|
|
841
922
|
# elements, the {Core::Items::Metadata::Hash} will be passed as an argument. Therefore it's
|
842
923
|
# recommended that you use a Proc, not a Lambda, for permissive argument matching.
|
843
924
|
#
|
844
|
-
# @return [
|
925
|
+
# @return [Hash] the prior provider configuration.
|
845
926
|
#
|
846
927
|
# @see provider
|
847
928
|
# @see OpenHAB::Core::Provider.current Provider.current for how the current provider is calculated
|
data/lib/openhab/rspec/shell.rb
CHANGED
@@ -5,26 +5,36 @@ module OpenHAB
|
|
5
5
|
# based on https://stackoverflow.com/questions/1197224/source-shell-script-into-environment-within-a-ruby-script#19826329
|
6
6
|
# @!visibility private
|
7
7
|
module Shell
|
8
|
-
|
8
|
+
# @!visibility private
|
9
|
+
DEFAULT_PRINTENV_COMMAND = "printenv -0"
|
10
|
+
@printenv_command = DEFAULT_PRINTENV_COMMAND
|
11
|
+
@printenv_separator = "\0"
|
9
12
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
cmd =
|
14
|
-
|
15
|
-
|
16
|
-
|
13
|
+
class << self
|
14
|
+
# Read in the bash environment, after an optional command.
|
15
|
+
# Returns Array of key/value pairs.
|
16
|
+
def shell_env(cmd = nil)
|
17
|
+
cmd = "#{cmd} > #{IO::NULL}; " if cmd
|
18
|
+
env = `#{cmd}#{@printenv_command} 2> #{IO::NULL}`
|
19
|
+
if !$?.success? && @printenv_command.equal?(DEFAULT_PRINTENV_COMMAND)
|
20
|
+
@printenv_command = "printenv"
|
21
|
+
@printenv_separator = "\n"
|
22
|
+
env = `#{cmd}#{@printenv_command}`
|
23
|
+
end
|
24
|
+
env.split(@printenv_separator).map { |l| l.split("=", 2) }
|
25
|
+
end
|
17
26
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
27
|
+
# Source a given file, and compare environment before and after.
|
28
|
+
# Returns Hash of any keys that have changed.
|
29
|
+
def shell_source(file)
|
30
|
+
(shell_env(". #{File.realpath(file)}") - shell_env).to_h
|
31
|
+
end
|
23
32
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
33
|
+
# Find variables changed as a result of sourcing the given file,
|
34
|
+
# and update in ENV.
|
35
|
+
def source_env_from(file)
|
36
|
+
shell_source(file).each { |k, v| ENV[k] = v }
|
37
|
+
end
|
28
38
|
end
|
29
39
|
end
|
30
40
|
end
|
@@ -9,7 +9,9 @@ module YARD
|
|
9
9
|
# Which might be a class, an enum, or an interface
|
10
10
|
module Base
|
11
11
|
module ClassMethods
|
12
|
-
def new(name)
|
12
|
+
def new(name, _suffix = nil)
|
13
|
+
# _suffix is given when it encounters a class with ::, e.g. org.openhab.core.OpenHAB::DEFAULT_CONFIG_FOLDER
|
14
|
+
|
13
15
|
super(:root, name)
|
14
16
|
end
|
15
17
|
end
|
@@ -5,27 +5,76 @@ module YARD
|
|
5
5
|
module JRuby
|
6
6
|
module Base
|
7
7
|
class << self
|
8
|
+
#
|
9
|
+
# Creates an external link to java documentation for a java class.
|
10
|
+
#
|
11
|
+
# The supported classes are defined in the `javadocs` configuration option.
|
12
|
+
#
|
13
|
+
# Supported syntaxes:
|
14
|
+
# Package:
|
15
|
+
# - org.openhab.core => href_base/org/openhab/core/package-summary.html
|
16
|
+
#
|
17
|
+
# Class:
|
18
|
+
# - org.openhab.core.OpenHAB => href_base/org/openhab/core/OpenHAB.html
|
19
|
+
# This doesn't get mistaken as a constant:
|
20
|
+
# - java.net.URI => href_base/java/net/URI.html
|
21
|
+
#
|
22
|
+
# Constant: (To specify a constant, use Ruby's `::` syntax)
|
23
|
+
# - org.openhab.core.OpenHAB::DEFAULT_CONFIG_FOLDER =>
|
24
|
+
# href_base/org/openhab/core/OpenHAB.html#DEFAULT_CONFIG_FOLDER
|
25
|
+
#
|
26
|
+
# Method:
|
27
|
+
# - org.openhab.core.OpenHAB#getVersion() => href_base/org/openhab/core/OpenHAB.html#getVersion()
|
28
|
+
# But can also work with constants, albeit not a valid Ruby syntax:
|
29
|
+
# - org.openhab.core.OpenHAB#version => href_base/org/openhab/core/OpenHAB.html#version
|
30
|
+
# - org.openhab.core.OpenHAB#DEFAULT_CONFIG_FOLDER =>
|
31
|
+
# href_base/org/openhab/core/OpenHAB.html#DEFAULT_CONFIG_FOLDER
|
32
|
+
#
|
33
|
+
# Inner class:
|
34
|
+
# - org.openhab.core.config.core.ConfigDescriptionParameter::Type =>
|
35
|
+
# href_base/org/openhab/core/config/core/ConfigDescriptionParameter.Type.html
|
36
|
+
# - org.openhab.core.config.core.ConfigDescriptionParameter.Type =>
|
37
|
+
# href_base/org/openhab/core/config/core/ConfigDescriptionParameter.Type.html
|
38
|
+
#
|
39
|
+
# Constant in inner class:
|
40
|
+
# - org.openhab.core.config.core.ConfigDescriptionParameter::Type::TEXT =>
|
41
|
+
# href_base/org/openhab/core/config/core/ConfigDescriptionParameter.Type.html#TEXT
|
42
|
+
# - org.openhab.core.config.core.ConfigDescriptionParameter.Type::TEXT =>
|
43
|
+
# href_base/org/openhab/core/config/core/ConfigDescriptionParameter.Type.html#TEXT
|
44
|
+
#
|
8
45
|
def infer_java_class(klass, inferred_type = nil, comments = nil, statement = nil)
|
9
|
-
components = klass.split(".")
|
10
|
-
components.pop if components.last == "freeze"
|
11
|
-
|
12
|
-
class_first_char = components.last[0]
|
13
|
-
is_field = components.last == components.last.upcase
|
14
|
-
container_first_char = components[-2]&.[](0)
|
15
|
-
is_method = container_first_char &&
|
16
|
-
class_first_char != class_first_char.upcase &&
|
17
|
-
container_first_char == container_first_char.upcase
|
18
|
-
is_package = !is_method && !is_field && class_first_char != class_first_char.upcase
|
19
|
-
|
20
|
-
# methods aren't supported right now
|
21
|
-
return if is_method
|
22
|
-
|
23
46
|
javadocs = YARD::Config.options.dig(:jruby, "javadocs") || {}
|
24
47
|
|
25
48
|
href_base = javadocs.find { |package, _href| klass == package || klass.start_with?("#{package}.") }&.last
|
26
49
|
return unless href_base
|
27
50
|
|
51
|
+
components = klass.split(/\.(?=[A-Z])/, 2)
|
52
|
+
components.unshift(*components.shift.split("."))
|
53
|
+
components.push(components.pop.delete_suffix(".freeze"))
|
54
|
+
|
55
|
+
class_first_char = components.last[0]
|
56
|
+
if /#|::/.match?(components.last)
|
57
|
+
parts = components.pop.rpartition(/#|::/)
|
58
|
+
is_field = parts.last == parts.last.upcase
|
59
|
+
# explicit method is fine, e.g. `org.openhab.core.OpenHAB#getVersion()`
|
60
|
+
is_method = !is_field
|
61
|
+
components.push(parts.first.gsub("::", "."), parts.last)
|
62
|
+
else
|
63
|
+
is_field = is_method = false
|
64
|
+
if components.last.include?(".")
|
65
|
+
parts = components.last.split(".")
|
66
|
+
if (is_method = parts.last[0] == parts.last[0].downcase)
|
67
|
+
# implicit method is not supported, e.g. `org.openhab.core.OpenHAB.version`
|
68
|
+
# because we're not sure whether it should be #version() or #getVersion()
|
69
|
+
return
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
is_package = !is_method && !is_field && class_first_char != class_first_char.upcase
|
75
|
+
|
28
76
|
inferred_type = CodeObjects::Java::FieldObject if is_field
|
77
|
+
inferred_type = CodeObjects::Java::MethodObject if is_method
|
29
78
|
inferred_type = CodeObjects::Java::PackageObject if is_package
|
30
79
|
if inferred_type.nil?
|
31
80
|
docstring = Docstring.parser.parse(comments || statement&.comments).to_docstring
|
@@ -36,12 +85,18 @@ module YARD
|
|
36
85
|
end
|
37
86
|
end
|
38
87
|
|
88
|
+
orig_klass = klass.dup
|
89
|
+
|
90
|
+
# purposely calling gsub! to modify the caller's string
|
91
|
+
# YARD doesn't handle java inner classes well, so we convert them to ruby
|
92
|
+
klass.gsub!("::", ".")
|
93
|
+
|
39
94
|
inferred_type.new(klass) do |o|
|
40
95
|
o.source = statement if statement
|
41
96
|
suffix = "/package-summary" if is_package
|
42
|
-
field = "##{components.pop}" if is_field
|
97
|
+
field = "##{components.pop}" if is_field || is_method
|
43
98
|
link = "#{href_base}#{components.join("/")}#{suffix}.html#{field}"
|
44
|
-
o.docstring.add_tag(Tags::Tag.new(:see,
|
99
|
+
o.docstring.add_tag(Tags::Tag.new(:see, orig_klass, nil, link)) unless o.docstring.has_tag?(:see)
|
45
100
|
end
|
46
101
|
end
|
47
102
|
end
|