openhab-scripting 5.10.0 → 5.12.0
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.
- 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
|